Swift Testing

Thimo Bess
arconsis
Published in
4 min readAug 12, 2024
Image made by Apple

Software testing is an essential component of software development and plays a crucial role in the quality and reliability of applications. One of the important aspects of testing is unit testing, which verifies individual code units in isolation.

Tests enable early error detection, identifying and resolving issues early in the development process. This saves time and costs by avoiding expensive fixes at later stages. Additionally, tests enhance code quality and maintainability by breaking down code into smaller, testable units, leading to improved architecture and more understandable code. Well-written tests also facilitate long-term software maintenance and help new developers onboard more quickly.

Swift Testing Logo made by Apple
Swift Testing Logo made by Apple

During this year’s WWDC 2024, Apple introduced a new testing framework called “Swift Testing”, which is designed to replace the existing XCTest. The new framework simplifies the writing of unit tests by replacing traditional expectations with macros, and combining all checks within a macro using #expect:

Example how to ise the #expect
Example from WWDC2024 made by Apple

Example: Calculator

Let’s assume we want to test a class named “Calculator.” The class looks like this:

class Calculator {
func add(_ a: Double, _ b: Double) -> Double {
return a + b
}

func subtract(_ a: Double, _ b: Double) -> Double {
return a - b
}

func multiply(_ a: Double, _ b: Double) -> Double {
return a * b
}

func divide(_ a: Double, _ b: Double) -> Double {
return a / b
}
}

First Unit Test

Let’s test our calculator with a first simple unit test that tests the addition of two numbers would look like this:

@Test func addTwoNumbers() async throws {
#expect(calculator.add(1, 1) == 2)
}

Custom Display Name for Test Methods

Since method names can sometimes be long and difficult to read, we can also assign a custom name using the test macro, which will be displayed in the test results in Xcode accordingly:

@Test("Add two numbers") func addTwoNumbers() async throws {
#expect(calculator.add(1, 1) == 2)
}
Custom test name in Xcode 16

Suites

By encapsulating multiple tests in a struct, we create a suite.

struct CalculatorTests {
@Test("Add two numbers")
func test_addTwoNumbers() async throws {
#expect(calculator.add(1, 1) == 2)
}
}

Using suites makes the test structure more readable. It is also possible to nest suites within each other, if desired.

Tags

Also new in Swift Testing is the ability to assign tags to each test to combine tests from different suites. When executing tests, you can specifically run all tests with a certain tag. You can create a tag using an extension on “Tag” with the Tag macro, like this:

extension Tag {
@Tag static let edgecase: Self
}

After the creation it can be added to the test trait:

@Test("Division by zero", .tags(.edgecase)) 
func divideNumberByZero() async throws {
#expect(calculator.divide(6, 0) == nil)
}

Parametrized Testing

Finally, with parametrized testing, tests that follow the same procedure but require different input parameters no longer need to be duplicated.

Consider the following test:

@Test("Multiply two numbers")
func multiplyNumbers() async throws {
#expect(calculator.multiply(1, 2) == 2)
}

If you want to execute the test with different parameters, you can do it like this:

@Test("Multiply two numbers", arguments: [
(1, 1, 1),
(1, 2, 2),
(2, 3, 6),
(10, 20, 200),
])
func multiplyNumbers(a: Double, b: Double, result: Double) async throws {
#expect(calculator.multiply(a, b) == result)
}

Now this test will run with all 4 variants:

Xcode Output of a parametrized test

In conclusion, Swift Testing represents a significant evolution in Apple’s approach to unit testing, offering developers a more intuitive and efficient way to ensure the quality and reliability of their code. By simplifying test writing with macros and introducing features like custom test method names, test suites, tags, and parameterized testing, Swift Testing not only enhances productivity but also fosters cleaner and more maintainable codebases.

It’s worth noting that Swift Testing is open source and can be accessed on GitHub, inviting collaboration and innovation within the developer community.

There are more features of this framework not covered in this article, so feel free to try it out and let me know your thoughts in the comments.

--

--