Unit Testing Strategies in SwiftUI
Written by Team Kodeco
Unit tests are designed to verify that individual parts of your code work as expected. These are typically small, quick and isolated tests that cover a single function or method. In SwiftUI, unit testing often involves testing models, logic or custom methods outside of the views.
Let’s consider a simple SwiftUI app with a counter that can be incremented and decremented. First, you’ll build the view and its associated view model.
Here’s a simple view model for your counter:
class CounterViewModel: ObservableObject {
@Published var count: Int = 0
func increment() {
count += 1
}
func decrement() {
count -= 1
}
}
This view model exposes two methods to increment and decrement the count and a published property to store the count’s current value.
Next, let’s define the view:
struct ContentView: View {
@StateObject var viewModel = CounterViewModel()
var body: some View {
VStack {
Text("Count: \(viewModel.count)")
Button("Increment", action: viewModel.increment)
Button("Decrement", action: viewModel.decrement)
}
}
}
Here’s what your preview should look like:
The view is simple, with two buttons to control the count and a text label to display it.
Unit Testing the View Model
You can write unit tests to ensure that the increment
and decrement
functions work correctly.
Creating a Test Case
Here’s how you might write a unit test for the CounterViewModel
. First, ensure your project has a unit testing bundle. If it doesn’t you can add one by selecting File ▸ New ▸ Target and choosing the Unit Testing Bundle template.
Then create a new file called CounterViewModelTests.swift
inside your tests group and add the following code:
import XCTest
@testable import SwiftUIToolkit
class CounterViewModelTests: XCTestCase {
func testIncrement() {
let viewModel = CounterViewModel()
viewModel.increment()
XCTAssertEqual(viewModel.count, 1)
}
func testDecrement() {
let viewModel = CounterViewModel()
viewModel.decrement()
XCTAssertEqual(viewModel.count, -1)
}
func testIncrementAndDecrement() {
let viewModel = CounterViewModel()
viewModel.increment()
viewModel.increment()
viewModel.decrement()
XCTAssertEqual(viewModel.count, 1)
}
}
Understanding the Tests
-
testIncrement
: Tests that the increment method increases the count by 1. -
testDecrement
: Tests that the decrement method decreases the count by 1. -
testIncrementAndDecrement
: Tests a sequence of incrementing and decrementing to ensure the logic handles multiple calls correctly.
Note: If your test target and main target have different names, make sure to replace
SwiftUIToolkit
with the actual name of your main target.
Running the Tests
To run the tests, press Command-U in Xcode, or select the play button next to the test class or individual test methods.
Here’s what Xcode’s test navigator looks like after running the tests:
Unit testing is a vital practice that helps you write more robust and maintainable code. In this example, you’ve explored how to test a simple view model in SwiftUI. These principles can be extended to more complex logic, such as networking or data transformations, to ensure your code behaves as expected under various conditions.