首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >带有NSURLSession模拟的KingFisher + UICollectionView + XCTest不加载图像

带有NSURLSession模拟的KingFisher + UICollectionView + XCTest不加载图像
EN

Stack Overflow用户
提问于 2017-08-30 13:55:20
回答 1查看 448关注 0票数 0

我正在为我的应用程序中的一些视图/视图控制器编写单元测试。

我的应用程序使用UICollectionView,单元格包含使用kingfisher加载的图像。我正在使用FBSnapshotTestCase记录视图的图像,并将它们与已知良好的图像进行比较(顺便说一句,当我们的开发人员自己拉取请求时,使用buddybuild's CI自动运行测试,这真的很酷)。

我使用NSURLSession-Mock将预先扫描的数据(包括JSON和图像)插入到测试中。

我的问题是,似乎很难编写测试来获得用户看到的最终结果;我经常发现这一点(除非图像已经缓存--因为我在测试设置中清除了缓存,以确保测试是从干净的状态运行的!)我拍摄的所有屏幕截图都缺少图像,只显示占位符。

EN

回答 1

Stack Overflow用户

发布于 2017-08-30 13:55:20

我已经找到了让它可靠工作的方法,但我看不出我对自己的解决方案是否100%满意。

首先,我在didFinishLaunchingWithOptions中这样做是为了避免加载应用程序的主UI,这会在尝试为应用程序的主屏幕编写测试时造成各种混乱:

代码语言:javascript
复制
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的设置,我需要这样做:

代码语言:javascript
复制
    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强制布局视图时,KingFisher才开始加载图像,并且( KingFisher通过将块分派到后台线程来加载图像,后台线程再将块分派回主线程)这太迟了-发送到主线程的块不能运行,因为主线程在FBSnapshotVerifyView()中被阻塞。如果没有对'layoutIfNeeded()‘和RunLoop.main.run()的调用,主队列的下一个测试GCD直到/ KingFisher / dispatch_async让运行循环运行才能运行,这已经太晚了。

我对我的解决方案不太满意。我不清楚为什么我需要layoutIfNeeded()两次并运行两次运行循环),所以我真的很欣赏其他的想法,但我希望这至少能帮助其他遇到同样情况的人,因为它需要一点挠头才能弄清楚发生了什么。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45952889

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档