2017-03-18 1 views
1

Vorbehalt - ich lese die paar Fragen über das Testen von Threads, aber möglicherweise die Antwort verpasst, wenn die Antwort da ist und ich es verpasste, bitte zeigen Sie mich in die richtige Richtung.Wie kann ich Einheit testen, dass ein Block des Codes auf DispatchQueue.main ausgeführt wird

Ich möchte testen, dass ein TableView-Aufruf zu reloadData in der Hauptwarteschlange ausgeführt wird.

Dies sollte Code sollte in einer vorübergehenden Prüfergebnis:

var cats = [Cat]() { 
    didSet { 
     DispatchQueue.main.async { [weak self] in 
      tableView.reloadData() 
     } 
    } 
} 

Dieser Code in einem fehlerhaften Test zur Folge haben sollte:

var cats = [Cat]() { 
    didSet { 
     tableView.reloadData() 
    } 
} 

Was sollte der Test aussehen?

Hinweis für die Testhasser: Ich weiß, dass dies eine einfache Sache zu fangen ist, aber es ist auch eine einfache Sache zu verpassen, wenn Sie Refactoring und Schichten von Abstraktion und mehrere Netzwerkaufrufe hinzufügen und aktualisieren möchten die UI mit einigen Daten, aber keine anderen Daten etc etc ... also bitte antworte nicht einfach mit "Updates auf UI gehe auf den Hauptthread" Ich weiß das schon. Vielen Dank!

Antwort

1

Verwenden dispatch_queue_set_specific Funktion, um ein Schlüssel-Wert-Paar mit den main queue

Dann dispatch_queue_get_specific verwenden zu assoziieren auf das Vorhandensein von Schlüsseln & Wert zu überprüfen:

fileprivate let mainQueueKey = UnsafeMutablePointer<Void>.alloc(1) 
fileprivate let mainQueueValue = UnsafeMutablePointer<Void>.alloc(1) 

/* Associate a key-value pair with the Main Queue */ 
dispatch_queue_set_specific(
    dispatch_get_main_queue(), 
    mainQueueKey, 
    mainQueueValue, 
    nil 
) 

func isMainQueue() -> Bool { 
    /* Checking for presence of key-value on current queue */ 
    return (dispatch_get_specific(mainQueueKey) == mainQueueValue) 
} 
0

I aufgewickelten Nehmen wir den verschachtelten Ansatz, einen zugeordneten Bool-Wert zu UITableView hinzuzufügen und dann UITableView zu switchen, um reloadData() umzuleiten

fileprivate let reloadDataCalledOnMainThreadString = NSUUID().uuidString.cString(using: .utf8)! 
fileprivate let reloadDataCalledOnMainThreadKey = UnsafeRawPointer(reloadDataCalledOnMainThreadString) 

extension UITableView { 
    var reloadDataCalledOnMainThread: Bool? { 
     get { 
      let storedValue = objc_getAssociatedObject(self, reloadDataCalledOnMainThreadKey) 
      return storedValue as? Bool 
     } 
     set { 
      objc_setAssociatedObject(self, reloadDataCalledOnMainThreadKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 
     } 
    } 

    dynamic func _spyReloadData() { 
     reloadDataCalledOnMainThread = Thread.isMainThread 

     _spyReloadData() 
    } 

    //Then swizzle that with reloadData() 
} 

Dann im Test habe ich die Katzen im Hintergrund Thread aktualisiert, so dass ich überprüfen konnte, ob sie auf den Hauptthread neu geladen wurden.

func testReloadDataIsCalledWhenCatsAreUpdated() { 
    // Checks for presence of another associated property that's set in the swizzled reloadData method 
    let reloadedPredicate = NSPredicate { [controller] _,_ in 
     controller.tableView.reloadDataWasCalled 
    } 
    expectation(for: reloadedPredicate, evaluatedWith: [:], handler: nil) 

    // Appends on the background queue to simulate an asynchronous call 
    DispatchQueue.global(qos: .background).async { [weak controller] in 
     let cat = Cat(name: "Test", identifier: 1) 
     controller?.cats.append(cat) 
    } 

    // 2 seconds seems excessive but NSPredicates only evaluate once per second 
    waitForExpectations(timeout: 2, handler: nil) 

    XCTAssert(controller.tableView.reloadDataCalledOnMainThread!, 
       "Reload data should be called on the main thread when cats are updated on a background thread") 
} 
+0

Die schnelle 3 Möglichkeit zu fragen, ob ein Thread ein gegebener Thread ist, ist die 'dispatchPrecondition (condition:)' globale Funktion. – matt

+0

@matt Ich kann sehen, wie Sie das in Produktionscode verwenden würden, um sicherzustellen, dass etwas auf dem Hauptthread ist, aber wie würden Sie das in einem Test verwenden? Ich nehme an, Sie würden behaupten, dass die Bedingung erfüllt ist, aber was wäre die Bedingung? –

Verwandte Themen