In Swift 6.2, we introduced the concept of an exit test: a section of code in a test function that would run in an independent process and allow test authors to test code that terminates the process. For example:
enum Fruit: Sendable, Codable, Equatable {
case apple, orange, olive, tomato
var isSweet: Bool { get }
consuming func feed(to bat: FruitBat) {
precondition(self.isSweet, "Fruit bats don't like savory fruits!")
...
}
}
@Test func `Fruit bats don't eat savory fruits`() async {
await #expect(processExitsWith: .failure) {
let fruit = Fruit.olive
let bat = FruitBat(named: "Chauncey")
fruit.feed(to: bat) // should trigger a precondition failure and process termination
}
}
I propose extending exit tests to support capturing state from the enclosing context (subject to several practical constraints):
@Test(arguments: [Fruit.olive, .tomato])
func `Fruit bats don't eat savory fruits`(_ fruit: Fruit) async {
await #expect(processExitsWith: .failure) { [fruit] in
let bat = FruitBat(named: "Chauncey")
fruit.feed(to: bat)
}
}
Read the full proposal here.
Trying it out
To try this feature out, add a dependency to the main
branch of swift-testing
to your project and enable the ExperimentalExitTestValueCapture
package trait[1]:
...
dependencies: [
...
.package(
url: "https://github.com/swiftlang/swift-testing.git",
branch: "main",
traits: [.defaults, "ExperimentalExitTestValueCapture",]
),
]
Then, add a target dependency to your test target:
.testTarget(
...
dependencies: [
...
.product(name: "Testing", package: "swift-testing"),
]
Finally, import Swift Testing using @_spi(Experimental) import Testing
.
Package traits require a package tools version of 6.2 or newer. You specify the package tools version with a comment at the top of Package.swift of the form
// swift-tools-version: 6.2
. ↩︎