UI and Snapshot Testing

Keep on testing, all the way to your Realm apps

While you're in the testing groove, start testing your apps. Apps powered by Realm are easy to test, since the database is simple and is designed to be testable. Have confidence is every part of your code!

Intro (0:00)

What is snapshot testing?

In snapshot testing, a view is rendered and saved into a repository. When the test is run, the tool re-creates and re-renders that view and does a comparison.

What can you test?

You can test states of your views, such as when it’s highlighted, or perhaps with more text. You can also test your view against different screen sizes.

Demo (3:19)

I’ve created a simple example with a view controller. The view has a title that animates, a body, and a button. This project is on GitHub

We’ll use SnapshotEngine as a wrapper, and Nimble-Snapshots to help with writing our tests.

Create a class that inherits from QuickSpec.

import UIKit
	import Quick
	import Nimble
	import Cartography
	@testable import cmduconf

	class ST_View: QuickSpec {
    
    	// Note: Return 'true' to regenerate the snapshots of this class
    	override var recordingMode: Bool {
    	    return false
    	}
    
    	let delegate = ViewController()
    
    	override func spec() {
        	describe("A View") {
            	context("on a 4' screen") {
                	let view = View(delegate: self.delegate)
                	constrain(view) { view in
                    	view.width == 320
                    	view.height == 568
                	}
                	it("has a valid snapshot") {
                    	expect(view).to(self.validateSnapshot())
                	}
            	}
            	context("on a 5.5' screen") {
                	let view = View(delegate: self.delegate)
                	constrain(view) { view in
                    	view.width == 414
                    	view.height == 736
                	}
                	it("has a valid snapshot") {
                    	expect(view).to(self.validateSnapshot())
                	}
            	}
        	}
    	}
	}

This test will fail because we don’t have a snapshot saved. Change the following line to true to save a snapshot to the repository.

// Note: Return 'true' to regenerate the snapshots of this class
    	override var recordingMode: Bool {
    	    return true
    	}

By changing the boolean back to false, the test will pass.

What happens under the hood?

It creates a snapshot by capturing the view and saving it to the repository. If the color of the view is changed, the test will fail.

These tests are created by a Facebook library, called FB Snapshot Test Case. The library creates a CGContextRef, and then creates another based on the saved snapshot. By rendering the view again, it compares both images on a memory level with a C function.

Concerns (10:45)

  • Architecture
    • You can test your view controllers, but if you isolate your views and separate them from the view controllers, that will be ideal.
  • Asynchronicity
    • If your views need network connectivity to work properly, it will be hard to test. To combat this, try to have methods that load a view without requiring a network connection.
  • Autolayout
    • Use autolayout. Views without autolayout requires the frame to be set.
  • Repo Space
    • Testing this way takes up repo space which can get clogged, and can take longer if its a large project.

Questions (16:35)

How can snapshot testing deal with animations?

You cannot test if something will change. You can only test the view in a fixed moment in time.

What is the difference between using snapshot testing versus UI testing for Xcode?

Firstly, snapshot testing is much faster. It runs with your unit tests so it’s not as if it runs the unit test and then runs the UI test. Secondly it doesn’t have to run the app so it’s faster that way.


Luis Ascorbe

Luis Ascorbe

Luis is the lead iOS develer @wallapop, and an organizer for NSSpain.

Transcribed by Joseph Buelow