Async teardown logic in swift-testing

Using XCTest I can have a func tearDown() async throws however with swift-testing, we are forced to do teardown logic in the deinit, which supports neither throwing nor async code.

What's the best way to run some common async teardown logic after each test using swift-testing?

1 Like

It looks like this is an active discussion here.

Looking forward to this landing, @smontgomery!

The other option is the withXXX approach we're using in Vapor, works well with structured concurrency

Have a link to an example? Did a cursory search in the vapor repo but couldn't find what you're referring to.

There's an example here jwt/Tests/JWTTests/Helpers/withApp.swift at main · vapor/jwt · GitHub. This function is then simply used as a wrapper in the tests jwt/Tests/JWTTests/JWTTests.swift at main · vapor/jwt · GitHub

3 Likes

For posterity’s sake, here’s how you can do it in Swift 6.1 and later:

struct AsyncTeardownTrait: TestTrait, TestScoping {
    func provideScope(
        for test: Test,
        testCase: Test.Case?,
        performing function: () async throws -> Void
    ) async throws {
        try await function()

        // Replace with your teardown logic.
        try await tearDown()
    }
}

extension Trait where Self == AsyncTeardownTrait {
    static var asyncTeardown: Self { Self() }
}

@Test(.asyncTeardown)
func doStuffWithAsyncTeardown() {
    // Test stuff.
}

One thing I’m not sure about is how to pass state from the test suite to the async teardown with this approach. :thinking:

Thanks this helps me also