Snapshot Testing Tutorial for SwiftUI: Getting Started
Learn how to test your SwiftUI iOS views in a simple and fast way using snapshot testing. By Vijay Subrahmanian.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Snapshot Testing Tutorial for SwiftUI: Getting Started
15 mins
- Getting Started
- What Is Snapshot Testing?
- Snapshot Testing Strategies
- Using the Image Strategy
- Testing the Row View
- Generating a Baseline Snapshot
- Introducing a UI Change
- Updating the Baseline Snapshot
- Testing the Detail View
- Setting up Your Testing Environment
- Testing for Specific iPhone Versions
- Testing for Device Orientation
- Testing for Dark Mode
- Finding the Baseline Snapshots
- Where to Go From Here?
When you’ve meticulously crafted a wonderful UI for your app, making sure it stays intact despite changes in the codebase is important. Among the many paths you can take to achieve this, snapshot testing is an effective option because it’s both lightning-fast and easy to create and maintain.
In this tutorial, you’ll use snapshot testing to validate your UIs, ensuring that code changes haven’t affected the UI you built. You’ll be using a simple library app, Ray’s Library, for creating these tests.
Specifically, you’ll learn how to:
- Create a baseline snapshot of the UI in your app and use it to validate any changes.
- Update the baseline snapshot when you’re redesigning the UI.
- Test the UI for different device types, orientations and traits.
Excited to get started? :]
Getting Started
Use the Download Materials button at the top or bottom of this tutorial to download the starter project.
The starter project is a simple app called Ray’s Library, which shows a list of — you guessed it! — books published by raywenderlich.com. The app was built using SwiftUI and incorporates the SnapshotTesting framework, using Swift Package Manager to test the UI.
Build and run in Xcode. Start by navigating through the app to familiarize yourself with it. The app has two screens, a landing screen and a book detail screen. The landing screen shows a list of books:
Scroll through the collection of books. Select any book from the list to view its detail screen, which includes a description and ratings:
Next, open BookRowView.swift and BookDetailView.swift to learn the UI layout. You’ll write snapshot tests for these UIs in the coming sections. But first, you’ll learn a little more about what snapshot testing is all about.
What Is Snapshot Testing?
Snapshot testing allows you to validate your UIs by comparing a snapshot of the UI at test time with a known valid snapshot of your UI, called a baseline. The test runner compares the current snapshot with the baseline snapshot. If there are any differences between the snapshots, the UI must have changed, so the test fails.
Snapshot Testing Strategies
The SnapshotTesting framework supports testing UIView
s and UIViewController
s using the image strategy or the recursive description strategy.
The image strategy takes actual snapshots of your UI as image files, then compares the images pixel by pixel. If the images are different, then the UI changed; your test will fail.
Similarly, the recursive description strategy compares string descriptions of the view hierarchy. If the descriptions have changed, your UI is different. Once again, your test will fail.
Finally, SnapshotTesting offers the hierarchy strategy, which generates the view controller hierarchy as plain text. Changes to the view controller hierarchy will cause your test to fail. Of course, this only works for UIViewController
tests.
Using the Image Strategy
For this tutorial, you’ll use the image strategy, where the framework compares the baseline image with the test image. The comparison works by checking for differences in the pixels of both images. Any difference in the pixels will cause your test to fail.
The image strategy supports many options while testing a UIViewController
:
- drawHierarchyInKeyWindow: Bool = false: Renders the view on the simulator’s Key Window and uses its appearance and visual effects.
-
on: ViewImageConfig: Lets you choose a variety of devices as the
ViewImageConfig
option. - precision: Float = 1: Indicates the percentage of pixels that must match for the test to pass. By default, it’s 1, which means 100% of the pixels must match.
- size: CGSize = nil: The view size for generating the snapshot of the test view.
- traits: UITraitCollection = .init(): Allows you to specify a plethora of traits to test with.
The first time you write and run a new test case, you’ll find that the test will fail. That’s because you don’t have a baseline snapshot yet. During the first run, SnapshotTesting will save the baseline snapshot to your project directory.
Subsequent test runs will take a new snapshot and compare it to the baseline.
Now, you’re ready to create your first snapshot test!
Testing the Row View
You’ll start by adding a test case to validate BookRowView
. Open BookRowViewTests.swift, and add the following line after the last import statement:
import SnapshotTesting
This imports the SnapshotTesting framework into your file.
Next, add these lines inside testBookRowView()
:
let bookRowView = BookRowView(book: sampleBook)
let view: UIView = UIHostingController(rootView: bookRowView).view
Here you’ve created an instance of BookRowView
, which is your SwiftUI view.
A SwiftUI view is a like a plan for a view, not a view itself. So you pass it to UIHostingController
as its rootView
and return a UIView
. Now, you have a view object you can test.
Generating a Baseline Snapshot
Before you can test your view, you need to generate a baseline snapshot. Add the line below to the end of testBookRowView()
:
assertSnapshot(
matching: view,
as: .image(size: view.intrinsicContentSize))
Here, you used assertSnapshot(matching:as:)
to assert that your view is valid. The SnapshotTesting framework provides assertSnapshot(matching:as:)
, which is similar to XCTAssert
. However, instead of simply comparing two values for equality, assertSnapshot(matching:as:)
compares two snapshots.
In this case, you passed your view
as the matching
parameter to tell SnapshotTesting which view you want to test. You’ve also directed SnapshotTesting to use the .image
strategy, meaning it will actually save a graphical representation of your UI view at its intrinsic content size.
Build and run the test by selecting Product ▸ Test from the menu bar or by typing Command-U. This will run all the tests in the test target.
Your test failed. To read the failure message, expand it by clicking the Cross icon.
The test failed because there was no reference snapshot to compare to the test result. Remember, the first time you execute your test case, the SnapshotTesting framework will create the baseline for you.
Now that you’ve created the baseline snapshot, build and run again. Success!
Great! Your first snapshot test