Writing Your First FBSnapshotTestCase

I’m in the thick of preparing for my talk at Philly CocoaHeads this week, but I wanted to get a quick post out that shows you how easy writing your first FBSnapshotTestCase is. Yesterday, I showed you how to setup FBSnapshotTestCase with Carthage. I’m going to assume you’ve done that already. I’ve create a sample project for my talk on Thursday that I’m going to use for this walkthrough on writing your first FBSnapshotTestCase. You can download that on GitHub here.

What You’ll Test

Open the application, and Build and Run.

writing your first FBSnapshotTestCase

You’ll see it’s a simple app, one that I’ve even used before in other posts. There’s two flows forward from this first screen, either with the Save, and continue button or the Continue, without saving button. If the user chooses, they may enter their name and tap Save, and continue to access the Welcome view where their name is shown to them.

writing your first FBSnapshotTestCase

Simple enough. In writing your first FBSnapshotTestCase, you are going to verify that the name specified shows up correctly on the Welcome view.

Take The Baseline Snapshot

To create the test, right-click the SnapshotTest group, and select New File:

writing your first FBSnapshotTestCase

Select Unit Test Case Class and Next:

writing your first FBSnapshotTestCase

Name the test WelcomeSnapshotTests and specify it as a Subclass of FBSnapshotTestCase. Click Next:

writing your first FBSnapshotTestCase

Click Create on the subsequent screen.

If you are prompted to create a bridging header, select Don’t create.

Now, Xcode will create the source file for you and drop you in it. The first thing to do is correctly import FBSnapshotTestCase.

Replace this:

import XCTest

with this:

import FBSnapshotTestCase
@testable import CocoaHeadsTestingPresentation

Importing CocoaHeadsTestingPresentation is necessary to access classes from that module so we can create views specific to the app. Now, you should be able to build with Command-B.

Delete everything within the WelcomeSnapshotTests class, and add this:

override func setUp() {
  super.setUp()
  recordMode = true
}

This setUp() method tells FBSnapshotTestCase that when recordMode is true, new snapshots will be taken. This requires the application to be in a “known good state.” That means that the view that you are going to “snapshot” looks just as you want it to look, because all future test runs will compare against this view.

Next, add this test method:

func testWelcomeView_WithName() {
  let welcomeVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("WelcomeViewController") as! WelcomeViewController
  welcomeVC.name = "Andy Obusek"
  FBSnapshotVerifyView(welcomeVC.view)
  FBSnapshotVerifyLayer(welcomeVC.view.layer)
}

This test creates a WelcomeViewController from a storyboard, specifies the name to be shown, and then verifies the view and layer.

Run this test. Just as usual, I suggest the keyboard shortcut Command-U. You’ll actually see the test fail:

writing your first FBSnapshotTestCase

But looking closer at the message:

Test ran in record mode. Reference image is now saved. Disable record mode to perform an actual snapshot comparison!

Nothing is actually wrong. FBSnapshotTestCase is just telling you that since it’s in recordMode, it will take new snapshots, but not let the test pass.

To see the snapshot, open the directory /SnapshotTests/ReferenceImages_64/SnapshotTests.SnapshotTests/. Inside that directory, you should see a png file that is the snapshotted view! So cool!

writing your first FBSnapshotTestCase

Turn Off Record Mode

Now that the baseline snapshot has been taken, turn recordMode off.

override func setUp() {
  super.setUp()
  recordMode = false
}

Now, rerun the test with Command-U. And bingo bango, the test passes! Light is green, trap is clean!.

Make Sure It Fails When It Needs To

It’s hard, if not impossible, to practice test driven development when writing your first FBSnapshotTestCase, or really any snapshot test at all. Since it requires the known “good state” to be snapshotted, some amount of real development has to happen first. That being said, you should still make sure that the test fails when it should. To do that, we’ll hack a bug into WelcomeViewController. Open WelcomeViewController.swift and add a few “eeee” to how the welcome message is set:

override func viewDidLoad() {
  super.viewDidLoad()
  if let name = name {
    welcomeLabel.text = "Welcomeeeeeeeee \(name)"
  } else {
    welcomeLabel.text = "Welcome Player 1"
  }
}

Re-run the test. It will fail! Whew, now we know that it will actually fail when it should.

Wrap Up

See, wasn’t it easy writing your first FBSnapshotTestCase? I hope snapshot testing helps you out. I’d love to hear how it helps you, or what you think of this approach. Please leave a comment!

Happy cleaning.

Leave a Reply

Your email address will not be published. Required fields are marked *