Moving from XCTest to Swift Testing
Swift Testing is Apple’s replacement for the objective-C XCTest unit testing framework. Discover how to migrate your existing XCTest suites over to Swift Testing, including how to get some assistance from Xcode’s agentic AI tooling. By Renan Benatti Dias.
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
Moving from XCTest to Swift Testing
35 mins
- Getting Started
- Updating Your First Unit Test
- Importance of Unit Testing
- Updating OrderModel
- Understanding @Suite
- Understanding @Test
- Updating Assertion Functions
- Migrating Async Methods
- Running Unit Tests in Serial
- Migrating XCTUnwrap Tests
- Putting Everything Together
- Migrating CoffeeShopTests
- Migrating Set Up and Tear Down Methods
- Migrating Callback Methods
- Failing Tests on Purpose
- Asserting Error Types
- Testing Methods That Should Not Throw Errors
- Using Traits
- Disabling and Enabling Unit Tests
- Tracking Bugs
- Limiting Test Run times
- Tagging Tests
- Using Parameters to Test Permutations
- Using Xcode 27 AI Skill to Migrate Unit Test
- Where to Go From Here
Tracking Bugs
Another useful trait Swift Testing has is the bug(_:id:_:) trait.
@Test(.bug("https://github.com/swiftlang/swift/pull/91471", id: 123, "Issue with cappuccino"))
@MainActor
func brewOrderReportsProgressForEachCoffee() async throws {
This trait allows you to annotate a test with a specific URL and ID of a bug report. It’s useful for tracking recurring bugs and regressions.
Limiting Test Run times
The timeLimit(_:) trait tells a unit test it must not run over the duration of time.
@Test(.timeLimit(.minutes(1)))
@MainActor
func brewOrderReportsProgressForEachCoffee() async throws {
Here, brewOrderReportsProgressForEachCoffee may not run longer than 1 minute and if it does, the unit test will fail.
Tagging Tests
You can also create tags to group specific unit tests.
extension Tag {
@Tag static var favoriteTests: Self
}
@Test(.tags(.favoriteTests))
@MainActor
func brewOrderReportsProgressForEachCoffee() async throws {
Xcode will group the tests in the Test Navigator with that tag, allowing you to run only those tests.
And the coolest part about Traits is that you can mix all of them:
@Test(
.tags(.favoriteTests),
.disabled(if: FeatureFlag.isBrewProgressEnabled == false),
.bug(id: 123)
)
@MainActor
func brewOrderReportsProgressForEachCoffee() async throws {
And you can even apply the same traits to an entire suite of tests:
@Suite(
.disabled(
if: Environment.isCI,
"Causing CI to run slow and burn credits."
),
.tags(.favoriteTests)
)
final class CoffeeShopTests {
Test traits are a great option to organize, document and modify tests in your project.
Using Parameters to Test Permutations
Another super power Swift Testing has is passing different parameters to a unit test. The method takes those parameters and runs a different test for each.
Back inside OrderModelTests.swift, add the following test method:
// 1
@Test(arguments: CoffeeKind.allCases, CoffeeSize.allCases)
func priceIsBasePriceTimesMultiplier(
// 2
kind: CoffeeKind,
size: CoffeeSize
) {
// 3
let coffee = Coffee(kind: kind, size: size)
let expected = ((kind.basePrice * size.priceMultiplier) * 100)
.rounded() / 100
#expect(coffee.price == expected)
}
Here’s the breakdown of this test:
- You declare a test method
priceIsBasePriceTimesMultiplierand you use theTest(_:arguments:_:)macro passing all cases ofCoffeeKindandCoffeeSize. - The test method takes as parameters a single
CoffeeKindandCoffeeSize - Finally, you have the code that tests the given
CoffeeKindandCoffeeSize
Run the unit test.

Swift Testing creates multiple implementations of priceIsBasePriceTimesMultiplier, each with a combination of CoffeeKind and CoffeeSize. That way, if a permutation of these two values does not follow the rules of pricing, you’ll see which combination of size and kind is failing.
Using Xcode 27 AI Skill to Migrate Unit Test
It’s no news that Xcode can leverage the power of agentic AI to help you code. And with Xcode 27, Apple is leaning even more on this. The latest version comes with built-in skills for AIs, skills written by Apple engineers to help AI write the best code for you.
One of those new skills is a skill to migrate XCTest to Swift Testing. That means you can task Xcode to migrate entire testing files for you with just a simple prompt.
While the skills you’re about to use are written by Apple engineers, remember that AI agents are not perfect. They still make mistakes and they can still generate bad code. So it’s ultimatley up to you to review, modify and polish code that AI writes.
Open the second Starter folder
The project is the same you worked on so far. All unit tests are using XCTest for now. But instead of migrating one by one, you’ll ask Xcode to do that for you.
At the navigation bar on the top, click the New Conversation button to open a new AI conversation.

Next, inside the message fields, enter the following prompt and click send:
Migrate OrderModelTests.swift to use Swift Testing
Xcode will task your AI agent to start the migration and it will load the skill that comes built into Xcode to do that.

Open OrderModelTests.swift and run the unit tests to make sure it’s working correctly.

Where to Go From Here
You can download the completed project files by clicking Download Materials at the top or bottom of the tutorial.
In this tutorial, you learned:
- How to migrate XCTest code to Swift Testing.
- How Swift Testing can be used alongside XCTest, allowing you to migrate code gradually.
- How to organize your tests and leverage Traits to do so.
- How to use parameters to create permutations of unit tests.
Additionally, you learned about Xcode 27’s AI skill that can help you migrate your code.
Eager to do more? SwiftBrew isn’t 100% covered by tests. Try writing more unit tests to achieve that or ask Xcode’s agentic AI to help you completely cover your project with unit tests.
We hope you enjoyed this tutorial. Please join the forum discussion below if you have any questions or comments!