ARTICLE AD BOX
This can be done with Test Scoping, introduced in ST-0007.
You can create a SuiteTrait that also conforms to TestScoping, and do your setup in the provideScope method.
struct DataLibraryTrait: SuiteTrait, TestScoping { func provideScope(for test: Test, testCase: Test.Case?, performing function: @Sendable () async throws -> Void) async throws { print("Setting up once and for all...") try await dataLibrary.load() try await function() print("Tearing down...") } } extension SuiteTrait where Self == DataLibraryTrait { static var useDataLibrary: DataLibraryTrait { .init() } }If you can apply this trait to a @Suite, the code before try await function() will be run once for all (not for each) of the tests/subsuites in that suite. Similarly, the code after try await function() will be run only once too.
As an example:
@Suite(.useDataLibrary) struct MyTestSuite { @Suite struct Subsuite1 { @Test func test1() async throws { print("Doing test 1") } @Test func test2() async throws { print("Doing test 2") } } @Suite struct Subsuite2 { @Test func test3() async throws { print("Doing test 3") } @Test func test4() async throws { print("Doing test 4") } } }Running MyTestSuite produces the output:
Suite MyTestSuite started. Setting up once and for all... Suite Subsuite2 started. Suite Subsuite1 started. Test test3() started. Test test4() started. Test test2() started. Doing test 3 Doing test 2 Test test3() passed after 0.001 seconds. Doing test 4 Test test1() started. Test test2() passed after 0.001 seconds. Test test4() passed after 0.001 seconds. Doing test 1 Test test1() passed after 0.001 seconds. Suite Subsuite2 passed after 0.001 seconds. Suite Subsuite1 passed after 0.001 seconds. Tearing down... Suite MyTestSuite passed after 0.001 seconds. Test run with 4 tests in 3 suites passed after 0.001 seconds. Program ended with exit code: 0