2014-11-18 29 views
7

I test si bloccano in modo casuale con waitForExpectation, sempre se soddisfo le aspettative in dispatch_after.Test di iOS si arresta in modo anomalo con waitForExpectationsWithTimeout

Succede sia in obiettivo-c che in rapido.

Totalmente a caso, a volte funziona a volte no. Qualcuno ha qualche idea? (Sono in esecuzione utilizzando CMD + U sul MacMini, ma ho anche provato con MBP Retina, stessi risultati) Codice

Esempio:

func testBarcodeNotFound() { 
     let exp = self.expectationWithDescription("store loading") 
     OHHTTPStubs.stubRequestsPassingTest({ (request:NSURLRequest!) -> Bool in 
      if request.URL.absoluteString == nil { 
       return false 
      } 
      return request.URL.absoluteString!.hasSuffix("/products/barcode/1422/") 
      }, withStubResponse: { (request:NSURLRequest!) -> OHHTTPStubsResponse! in 
       let data = "".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true) 
       return OHHTTPStubsResponse(data: data, statusCode: 404, headers: ["Content-Type":"application/json"]) 

     }) 
     self.productsVC.scanningVC.successScan("1422", "EAN13") 
     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.5 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {() -> Void in 
      exp.fulfill() 
     } 

     self.waitForExpectationsWithTimeout(1, handler: nil) 

     XCTAssertTrue(self.delegateForProductsVC.barcodeNotFoundCalled) 

    } 

E Backtrace

(lldb) bt 
* thread #1: tid = 0x27e405, 0x06461ab0 libdispatch.dylib`_dispatch_semaphore_dispose + 92, queue = 'com.apple.main-thread', stop reason = EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) 
    frame #0: 0x06461ab0 libdispatch.dylib`_dispatch_semaphore_dispose + 92 
    frame #1: 0x06463578 libdispatch.dylib`_dispatch_dispose + 43 
    frame #2: 0x064759e1 libdispatch.dylib`_os_object_dispose + 33 
    frame #3: 0x06475cb1 libdispatch.dylib`-[OS_dispatch_object _xref_dispose] + 58 
    frame #4: 0x064759bb libdispatch.dylib`_os_object_xref_dispose + 33 
    frame #5: 0x05759eb1 libobjc.A.dylib`objc_release + 65 
    frame #6: 0x2011949d XCTest`__destroy_helper_block_95 + 29 
    frame #7: 0x064e4793 libsystem_sim_blocks.dylib`_Block_release + 211 
    frame #8: 0x0647603f libdispatch.dylib`_dispatch_client_callout + 14 
    frame #9: 0x0645f764 libdispatch.dylib`_dispatch_main_queue_callback_4CF + 470 
    frame #10: 0x05af095e CoreFoundation`__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 14 
    frame #11: 0x05aaf760 CoreFoundation`__CFRunLoopRun + 2256 
    frame #12: 0x05aaebcb CoreFoundation`CFRunLoopRunSpecific + 443 
    frame #13: 0x05aae9fb CoreFoundation`CFRunLoopRunInMode + 123 
    frame #14: 0x04c2ed98 Foundation`-[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 309 
    frame #15: 0x20119a31 XCTest`-[XCTestCase(AsynchronousTesting) waitForExpectationsWithTimeout:handler:] + 1192 
    * frame #16: 0x1055be0b SomeAppNative`SomeApp.ProductsDelegatesViewControllerTest.testBarcodeNotFound (self=0x7b0dbdf0)() ->() + 5595 at ProductsDelegatesViewControllerTest.swift:108 
    frame #17: 0x1055c1a2 SomeAppNative`@objc SomeApp.ProductsDelegatesViewControllerTest.testBarcodeNotFound (SomeApp.ProductsDelegatesViewControllerTest)() ->() + 34 at ProductsDelegatesViewControllerTest.swift:0 
    frame #18: 0x05a7976d CoreFoundation`__invoking___ + 29 
    frame #19: 0x05a79618 CoreFoundation`-[NSInvocation invoke] + 360 
    frame #20: 0x2010897b XCTest`-[XCTestCase invokeTest] + 320 
    frame #21: 0x20108bb9 XCTest`-[XCTestCase performTest:] + 184 
    frame #22: 0x20114162 XCTest`-[XCTest run] + 314 
    frame #23: 0x20107598 XCTest`-[XCTestSuite performTest:] + 406 
    frame #24: 0x20114162 XCTest`-[XCTest run] + 314 
    frame #25: 0x20107598 XCTest`-[XCTestSuite performTest:] + 406 
    frame #26: 0x20114162 XCTest`-[XCTest run] + 314 
    frame #27: 0x20107598 XCTest`-[XCTestSuite performTest:] + 406 
    frame #28: 0x20114162 XCTest`-[XCTest run] + 314 
    frame #29: 0x20103de2 XCTest`__25-[XCTestDriver _runSuite]_block_invoke + 61 
    frame #30: 0x20110c82 XCTest`-[XCTestObservationCenter _observeTestExecutionForBlock:] + 184 
    frame #31: 0x20103d06 XCTest`-[XCTestDriver _runSuite] + 285 
    frame #32: 0x20104951 XCTest`-[XCTestDriver _checkForTestManager] + 272 
    frame #33: 0x20104c6b XCTest`-[XCTestDriver runTestSuite:completionHandler:] + 378 
    frame #34: 0x2011775c XCTest`+[XCTestProbe runTests:] + 216 
    frame #35: 0x04c2ab57 Foundation`__NSFireDelayedPerform + 423 
    frame #36: 0x05af08d6 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 22 
    frame #37: 0x05af025d CoreFoundation`__CFRunLoopDoTimer + 1309 
    frame #38: 0x05aaf6ba CoreFoundation`__CFRunLoopRun + 2090 
    frame #39: 0x05aaebcb CoreFoundation`CFRunLoopRunSpecific + 443 
    frame #40: 0x05aae9fb CoreFoundation`CFRunLoopRunInMode + 123 
    frame #41: 0x0712e24f GraphicsServices`GSEventRunModal + 192 
    frame #42: 0x0712e08c GraphicsServices`GSEventRun + 104 
    frame #43: 0x034518b6 UIKit`UIApplicationMain + 1526 
    frame #44: 0x0053dae5 SomeApp`main(argc=16, argv=0xbff6e4a4) + 213 at main.m:16 
    frame #45: 0x0649cac9 libdyld.dylib`start + 1 
(lldb) 

risposta

0

ho avuto la stesso problema. La correzione per me sembrava aumentare l'intervallo di timeout. Inizialmente avevo un intervallo di timeout di 1 e lo aumentavo a 5 solo per essere al sicuro. Sembra funzionare bene ora. Non sono sicuro di quanto dura la tua chiamata asincrona o se puoi permetterti un intervallo di timeout più lungo di 1, ma vale la pena provare.

+0

Ho provato questo, nel 50% dei casi ha aiutato. Puoi vedere nel codice che ho postato che async è solo "dispatch_after" che aspetta "0.5s". Alla fine, sto aspettando l'attesa dopo il blocco di attesa e facendo tutti i richiami anche dopo il blocco di attesa. Quindi non succede nulla durante l'attesa, ma adempiere. –

0

Swift presenta un problema speciale per mostrare il punto di interruzione delle eccezioni corretto quando le chiusure sono presenti nello stesso ambito.

Ho visto lo stesso problema in un XCTestCase che usati dispatch_after e anche attraverso il punto di interruzione eccezione era la stessa linea waitForExpectationsWithTimeout caso prova stava arrestando a causa di un abbattuto su un oggetto nullo.

So che questo non è il tuo caso, ma ogni volta che ciò accade suggerisco di rimuovere le istruzioni una riga alla volta e di eseguire il test dopo ogni rimozione. Se il test non si blocca, hai identificato il colpevole. Questa è, purtroppo, l'opzione migliore al momento in cui scrivo ogni volta che Swift mostra un punto d'interruzione di eccezione su una linea che non ha senso, specialmente la famigerata riga 0 di una classe che potresti vedere negli strumenti di segnalazione degli arresti anomali.

Facci sapere se hai scoperto il tuo incidente.

1

Ho riscontrato problemi simili e mi ci sono voluti tre giorni per capire.

La documentazione di -waitForExpectationsWithTimeout:handler: dice:

* -waitForExpectationsWithTimeout:handler: runs the run loop while handling events until all expectations 
* are fulfilled or the timeout is reached. Clients should not manipulate the run 
* loop while using this API. 

Molto probabilmente il NSInputStream o NSOutputStream sta cercando di influenzare il runloop durante l'attesa, che causerà un crash.

Problemi correlati