Concurrency-Safe Testing in Swift 6.1 with @TaskLocal and Test Scoping

Concurrency-Safe Testing in Swift 6.1 with @TaskLocal and Test Scoping

Today’s example shows a static property providing the current date. Perfect mechanism when we don’t want to inject it everywhere where it’s used. How to test it? Check it out ⤵️ Initial setup let currentDateFormatter: DateFormatter = { let formatter = DateFormatter() formatter.dateStyle = .short formatter.timeStyle = .none return formatter }() var currentDateFormatted: String { currentDateFormatter.string(from: DateEnvironment.currentDate()) } enum DateEnvironment { static var currentDate: () -> Date = Date.init } extension Date { // 16.04.2025 static let sixteenthOfApril = Date(timeIntervalSince1970: 1744840515) } Old way - XCTest Override the static property in tests. Works, but not concurrency-safe (Ok, for XCTest because test ran serially). class CurrentDateFormatterTests: XCTestCase { func test_dateFormatting() { // ✅ DateEnvironment.currentDate = { .sixteenthOfApril } XCTAssertEqual(currentDateFormatted, "16.04.2025") } } Swift Testing before Swift 6.1 enum DateEnvironment { @TaskLocal static var currentDate: () -> Date = Date.init } struct CurrentDateFormatterTests { @Test func dateFormatting() { // ✅ DateEnvironment.$currentDate .withValue({ .sixteenthOfApril }) { #expect(currentDateFormatted == "16.04.2025") } } } Why @TaskLocal? ...

May 7, 2025 · 2 min · Maciej Gomolka
3 Ways to Name Parameters in Swift Parametrised Tests

3 Ways to Name Parameters in Swift Parametrised Tests

Mind your argument names in Swift Testing’s parametrised tests! As a follow up to my recent post on refactoring to use Swift Testing’s parametrised tests, I’m diving into the crucial - yet often overlooked topic of how to name your parametrised test inputs. Option 1: First Named Tuples Only the first tuple is named, all others rely on positional matching to (a, b, result). ✅ Minimal boilerplate for small input sets ❌ Readability drops after adding more cases ❌ Easy to mix up arguments position ❌ Hard to scan or extend func add(_ a: Int, _ b: Int) -> Int { a + b } ... @Test(arguments: [ (a: 1, b: 2, result: 3), (10, 15, 25), (1, -5, -4), (-1, -5, -6), (0, 0, 0), (1000, 1000, 2000), (10000, 50000, 60000), (-10, -3, -13) ]) func add_returnsCorrectSum(a: Int, b: Int, result: Int) { #expect(add(a, b) == result) } Option 2: Named Tuples Every tuple entry explicitly names all its fields (a: …, b: …, result: …) for all cases. ...

April 24, 2025 · 3 min · Maciej Gomolka
Swift Testing Challange - Can you refactor this?

Swift Testing Challange - Can you refactor this?

Intro Have you already started using Swift Testing instead of XCTest? I’m curious to see how you can refactor the test function (add_returnsCorrectSum) from the code snippet to use all powers of the Swift Testing framework. Could you explain what benefits does your refactored version has compared to my original code snippet? My approach In both approaches the test gives the same result. The point is the refactored version uses a Swift Testing parametrised test, and this makes a real difference. ...

April 17, 2025 · 2 min · Maciej Gomolka
#7 XCTest vs Swift Testing: A modern way of linking bugs

#7 XCTest vs Swift Testing: A modern way of linking bugs

What’s the difference? In XCTest we relied on the old fashioned simple comments to add more context to our test case e.g link to the bug description. With Swift Testing, we now have a special bug trait that can be passed to the @Test macro. The bug trait takes a URL String as argument and optionally a title for the bug allowing us to add short description of it. The key advantage over regular comment is that the bug title is visible in the test results. Better yet, tapping on it takes you directly to the related webpage with the bug report. ...

December 13, 2024 · 2 min · Maciej Gomolka
#6 XCTest vs Swift Testing - Parameterized tests in the fight for more reusable code

#6 XCTest vs Swift Testing - Parameterized tests in the fight for more reusable code

What’s the difference? XCTest doesn’t provide a built-in solution for parameterized tests. To achieve this, we create test cases as structs or tuples, defining test inputs and expected results. Then, we write a loop to iterate through these test cases and execute the necessary assertions. Swift Testing simplifies this process by allowing tests to be parameterized directly. Using the @Test macro, you can pass test cases as an argument. What’s the benefit? While you still need to define your test cases, the iteration code is no longer needed — Swift Testing handles it for you. ...

December 5, 2024 · 2 min · Maciej Gomolka