Snapshot Testing Tutorial for SwiftUI: Getting Started
- 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? :]
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
UIViewControllers 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
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
- 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
- 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:
This imports the SnapshotTesting framework into your file.
Next, add these lines inside
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
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