In 2021, Apple launched Swift concurrency to an adoring viewers; lastly, builders might write Swift code to implement concurrency in Swift apps! At WWDC 2024, builders received one other sport changer: Swift Testing. It’s so a lot enjoyable to make use of, you’ll be leaping off the bed each morning, keen to write down extra unit checks for all of your apps! No extra gritting your enamel over XCTAssert-this-and-that. You get to write down in Swift, utilizing Swift concurrency, no much less. Swift Testing is a factor of magnificence, and Apple’s testing staff is rightfully happy with its achievement. You’ll be capable to write checks quicker and with better management, your checks will run on Linux and Home windows, and Swift Testing is open supply, so you might help to make it even higher.
Swift Testing vs. XCTest
Right here’s a fast checklist of variations:
- You mark a perform with
@Take a look at
as an alternative of beginning its identify withtake a look at
. - Take a look at capabilities will be occasion strategies, static strategies, or world capabilities.
- Swift Testing has a number of traits you should use so as to add descriptive details about a take a look at, customise when or whether or not a take a look at runs, or modify how a take a look at behaves.
- Assessments run in parallel utilizing Swift concurrency, together with on gadgets.
- You utilize
#anticipate(...)
orstrive #require(...)
as an alternative ofXCTAssertTrue
,...False
,...Nil
,...NotNil
,...Equal
,...NotEqual
,...An identical
,...NotIdentical
,...GreaterThan
,...LessThanOrEqual
,...GreaterThanOrEqual
or...LessThan
.
Preserve studying to see extra particulars.
Getting Began
Word: You want Xcode 16 beta to make use of Swift Testing.
Click on the Obtain Supplies button on the prime or backside of this text to obtain the starter initiatives. There are two initiatives so that you can work with:
Migrating to Swift Testing
To start out, open the BullsEye app in Xcode 16 beta and find BullsEyeTests within the Take a look at navigator.
These checks test that BullsEyeGame
computes the rating accurately when the person’s guess is increased or decrease than the goal.
First, remark out the final take a look at testScoreIsComputedPerformance()
. Swift Testing doesn’t (but) assist UI efficiency testing APIs like XCTMetric
or automation APIs like XCUIApplication
.
Return to the highest and substitute import XCTest
with:
import Testing
Then, substitute class BullsEyeTests: XCTestCase {
with:
struct BullsEyeTests {
In Swift Testing, you should use a struct, actor, or class. As standard in Swift, struct
is inspired as a result of it makes use of worth semantics and avoids bugs from unintentional state sharing. In case you should carry out logic after every take a look at, you’ll be able to embrace a de-initializer. However this requires the sort to be an actor or class — it’s the most typical motive to make use of a reference kind as an alternative of a struct.
Subsequent, substitute setUpWithError()
with an init
methodology:
init() {
sut = BullsEyeGame()
}
This allows you to take away the implicit unwrapping from the sut
declaration above:
var sut: BullsEyeGame
Remark out tearDownWithError()
.
Subsequent, substitute func testScoreIsComputedWhenGuessIsHigherThanTarget() {
with:
@Take a look at func scoreIsComputedWhenGuessIsHigherThanTarget() {
and substitute the XCTAssertEqual
line with:
#anticipate(sut.scoreRound == 95)
Equally, replace the second take a look at perform to:
@Take a look at func scoreIsComputedWhenGuessIsLowerThanTarget() {
// 1. given
let guess = sut.targetValue - 5
// 2. when
sut.test(guess: guess)
// 3. then
#anticipate(sut.scoreRound == 95)
}
Then, run BullsEyeTests within the standard manner: Click on the diamond subsequent to BullsEyeTests within the Take a look at navigator or subsequent to struct BullsEyeTests
within the editor. The app builds and runs within the simulator, after which the checks full with success:
Now, see how simple it’s to vary the anticipated situation: In both take a look at perform, change ==
to !=
:
#anticipate(sut.scoreRound != 95)
To see the failure message, run this take a look at after which click on the purple X:
And click on the Present button:
It exhibits you the worth of sut.scoreRound
.
Undo the change again to ==
.
Discover the opposite take a look at teams are nonetheless there, and so they’re all XCTests. You didn’t should create a brand new goal to write down Swift Testing checks, so you’ll be able to migrate your checks incrementally. However don’t name XCTest assertion capabilities from Swift Testing checks or use the #anticipate
macro in XCTests.
Including Swift Testing
Shut BullsEye and open TheMet. This app has no testing goal, so add one:
Testing System defaults to Swift Testing:
Now, take a look at your new goal’s Common/Deployment Information:
Not surprisingly, it’s iOS 18.0. However TheMet’s deployment is iOS 17.4. You possibly can change one or the opposite, however they should match. I’ve modified TheMet’s deployment to iOS 18.
Open TheMetTests within the Take a look at navigator to see what you bought:
import Testing
struct TheMetTests {
@Take a look at func testExample() async throws {
// Write your take a look at right here and use APIs like `#anticipate(...)` to test anticipated circumstances.
}
}
You’ll want the app’s module, so import that:
@testable import TheMet
You’ll be testing TheMetStore
, the place all of the logic is, so declare it and initialize it:
var sut: TheMetStore
init() async throws {
sut = TheMetStore()
}
Press Shift-Command-O, kind the, then Possibility-click TheMetStore.swift to open it in an assistant editor. It has a fetchObjects(for:)
methodology that downloads at most maxIndex
objects. The app begins with the question “rhino”, which fetches three objects. Exchange testExample()
with a take a look at to test that this occurs:
@Take a look at func rhinoQuery() async throws {
strive await sut.fetchObjects(for: "rhino")
#anticipate(sut.objects.depend == 3)
}
Run this take a look at … success!
Write one other take a look at:
@Take a look at func catQuery() async throws {
strive await sut.fetchObjects(for: "cat")
#anticipate(sut.objects.depend <= sut.maxIndex)
}
Parameterized Testing
Once more, it succeeds! These two checks are very comparable. Suppose you need to take a look at different question phrases. You can maintain doing copy-paste-edit, however top-of-the-line options of Swift Testing is parameterized checks. Remark out or substitute your two checks with this:
@Take a look at("Variety of objects fetched", arguments: [
"rhino",
"cat",
"peony",
"ocean",
])
func objectsCount(question: String) async throws {
strive await sut.fetchObjects(for: question)
#anticipate(sut.objects.depend <= sut.maxIndex)
}
And run the take a look at:
The label and every of the arguments seem within the Take a look at navigator. The 4 checks ran in parallel, utilizing Swift concurrency. Every take a look at used its personal copy of sut
. If one of many checks had failed, it would not cease any of the others, and also you’d be capable to see which of them failed, then rerun solely these to search out the issue.