2017-08-30 71 views
0

我正在爲我的應用程序中的一些視圖/ viewcontrollers編寫單元測試。KingFisher + UICollectionView + XCTest與NSURLSession模擬不會加載圖像

我的應用使用UICollectionView,其中包含使用kingfisher加載的圖像。我正在使用FBSnapshotTestCase來記錄視圖的圖像,並將它們與已知的良好圖像進行比較(並作爲旁白,使用buddybuild's CI在我們的開發人員擁有拉取請求時自動運行測試,這非常酷)。

我正在使用NSURLSession-Mock將預分析數據(包括JSON和圖像)插入到測試中。

我的問題是,似乎很難寫測試,得到最終的相同的最終結果用戶看到;我經常發現(除非圖像已經被緩存 - 他們不是,因爲我在測試的設置中清除了緩存,以確保測試從乾淨狀態運行!)我採取的所有屏幕截圖都缺少圖像,只顯示佔位符。

回答

0

我已經找到了一些可以可靠工作的方法,但是我看不出我對解決方案100%滿意。

首先,我在didFinishLaunchingWithOptions避免應用程序的主界面做到這一點得到加載,由此引起的一切排序混亂的時候也嘗試寫應用程序的主屏幕測試:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 
    BuddyBuildSDK.setup() 

    //Apply Itison UI Styles 
    ItIsOnUIAppearance.apply() 

    #if DEBUG 
    if let _ = NSClassFromString("XCTest") { 
     // If we're running tests, don't launch the main storyboard as 
     // it's confusing if that is running fetching content whilst the 
     // tests are also doing so. 
     let viewController = UIViewController() 
     let label = UILabel() 
     label.text = "Running tests..." 
     label.frame = viewController.view.frame 
     label.textAlignment = .center 
     label.textColor = .white 
     viewController.view.addSubview(label) 
     self.window!.rootViewController = viewController 
     return true 
    } 
    #endif 

然後在測試中,一旦我已經完全建立在的UIViewController我需要做這樣的事情:

func wait(for duration: TimeInterval) { 
     let waitExpectation = expectation(description: "Waiting") 

     let when = DispatchTime.now() + duration 
     DispatchQueue.main.asyncAfter(deadline: when) { 
      waitExpectation.fulfill() 
     } 

     waitForExpectations(timeout: duration+1) 
    } 

    _ = viewController.view // force view to load 
    viewController.viewWillAppear(true) 
    viewController.view.layoutIfNeeded() // forces view to layout; necessary to get kingfisher to fetch images 

    // This is necessary as otherwise the blocks that Kingfisher 
    // dispatches onto the main thread don't run 
    RunLoop.main.run(until: Date(timeIntervalSinceNow:0.1)); 
    viewController.view.layoutIfNeeded() // forces view to layout; necessary to get kingfisher to fetch images 

    wait(for: 0.1) 
    FBSnapshotVerifyView(viewController.view) 

,如果我不這樣做的基本問題是,翠鳥只有啓動時FBSnapshotVerifyView迫使視圖加載圖像被解僱(和Ki一樣ngFisher通過將塊分派給後臺線程來加載映像,後臺線程然後將塊分派回主線程),這太遲了 - 發送到主線程的塊無法運行,因爲主線程在FBSnapshotVerifyView()中被阻塞。沒有對'layoutIfNeeded()'和RunLoop.main.run()的調用,KingFisher dispatch_async GCD到主隊列不會運行,直到/ next/test讓runloop運行,這太遲了。我不太滿意我的解決方案(例如,爲什麼我需要layoutIfNeeded()兩次並運行runloop兩次),所以我會非常欣賞其他想法,但我希望這至少可以幫助其他人這種情況發生在同樣的情況下,因爲它需要一點頭腦才能弄清楚發生了什麼。