I'm writing unit tests for some of the views/viewcontrollers in my apps.
My app uses UICollectionView, with the cells containing images loaded using kingfisher. I am using FBSnapshotTestCase to record images of the view and compare them against known good images (and as an aside, using buddybuild's CI to automate running the tests when our developers own pull requests, which is really cool).
I'm using NSURLSession-Mock to insert precanned data (both JSON and images) into the tests.
My problem is that it seems hard to write tests that get the final same end result the users see; I'm frequently finding that (unless the images are already cached - which they aren't as I clear out the cache in test's setup to make sure the tests are running from a clean state!) all the screenshots I take are missing the images, showing only the placeholders.
I've found ways to get this apparently working reliably, but I can't see that I'm 100% happy with my solutions.
Firstly I do this in didFinishLaunchingWithOptions to avoid the application's main UI getting loaded, which caused all sort of confusion when also trying to write tests for the app's home screen:
then in the test, once I've fully setup the UIViewController I need to do things like this:
The basic issue if I don't do this is that KingFisher only starts to load the images when the FBSnapshotVerifyView forces the view to be laid out, and (as KingFisher loads images by dispatching blocks to background threads, which then dispatch blocks back to the main thread) this is too late - the blocks sent to the main thread can't run as the main thread is blocked in FBSnapshotVerifyView(). Without the calls to 'layoutIfNeeded()' and RunLoop.main.run() the KingFisher dispatch_async GCD to the main queue doesn't get to run until the /next/ test lets the runloop run, which is far too late.
I'm not too happy with my solution (eg. it's far from clear why I need to layoutIfNeeded() twice and run the runloop twice) so would really appreciate other ideas, but I hope this at least helps other people that run into the same situation as it took a little bit of head scratching to figure out what was happening.