# Are trait stored properties shared across all tests when attached at the @Suite level?

**URL:** <https://forums.swift.org/t/are-trait-stored-properties-shared-across-all-tests-when-attached-at-the-suite-level/79244>\
**Category:** Swift Testing\
**Tags:** swift-testing\
**Created:** [April 13, 2025, 2:48am UTC](https://forums.swift.org/t/are-trait-stored-properties-shared-across-all-tests-when-attached-at-the-suite-level/79244 "2025-04-13T02:48:36Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![pavm035](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/pavm035/32/18274_2.png) [@pavm035](https://forums.swift.org/u/pavm035)\
**Post date:** [April 13, 2025, 2:48am UTC](https://forums.swift.org/t/are-trait-stored-properties-shared-across-all-tests-when-attached-at-the-suite-level/79244/1 "2025-04-13T02:48:36Z")

</div>

Hi all 👋,

I'm exploring the new Swift Testing framework, and came across a behavior I'd like to confirm.

Let’s say I define a custom trait like this:

```swift
struct MyTrait: TestTrait, TestScoping {
    let value: UUID = UUID()

    func provideScope(
        for test: Test,
        testCase: Test.Case?,
        performing function: @Sendable () async throws -> Void
    ) async throws {
        print("Trait value:", value)
        try await function()
    }
}

```

And apply it like this:

```swift
@Suite("MySuite", MyTrait())
struct MyTests {
    @Test func test1() { }
    @Test func test2() { }
}

```

When I run the tests, both `test1` and `test2` print the **same `UUID`** , meaning the same `MyTrait` instance is reused — even though `provideScope()` is called separately for each test.

However, if I attach `MyTrait()` individually to each test, the UUID is different — which suggests a fresh trait instance is used per test.

### ❓ My Question:

Is it expected behavior that:

- Traits applied at the `@Suite` level are **created once** and **shared** across all tests in the suite?
- Even though `provideScope()` is called per test, all tests access the same stored properties?

If so, would the best practice be to:

- Avoid storing per-test data in suite-level trait properties?
- Use helper methods or closures to generate fresh values inside `provideScope()`?

Thanks for the clarification!

---

<div class="post-metadata">

**Author:** ![smontgomery](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/smontgomery/32/965_2.png) [@smontgomery](https://forums.swift.org/u/smontgomery)\
**Post date:** [April 13, 2025, 3:25am UTC](https://forums.swift.org/t/are-trait-stored-properties-shared-across-all-tests-when-attached-at-the-suite-level/79244/2 "2025-04-13T03:25:08Z")

</div>

Hey @pavm035,

A couple things to note first:

- As written, this code doesn't compile because `MyTrait` doesn't conform to `SuiteTrait`. Only trait types which conform to `SuiteTrait` may be applied to suites via the `@Suite(...)` attribute. I'll assume in your "real" code you did have this conformance, though.
- A trait applied to a `@Suite(...)` is only inherited by the `@Test` functions within that suite if it overrides the `SuiteTrait.isRecursive` property to `true`. Otherwise, the trait only applies to the suite itself, and, if the trait also conforms to `TestScoping`, the `provideScope()` method is only called once, for the suite itself, rather than being called once for each of the suite's test functions.

Given that, I'll try to answer your questions:

> [@pavm035](#):
>
> Is it expected behavior that:
> 
> - Traits applied at the `@Suite` level are **created once** and **shared** across all tests in the suite?

It depends on the `isRecursive` property, as I mentioned above. But even if `isRecursive` is `true`, a _copy_ of the trait applied to the suite is what will be inherited by its test functions. When a trait from a suite is inherited by a test function, it does not re-evaluate the expression which was originally used to create the trait instance (`MyTrait()`), so in this example the `MyTrait` value gets copied to the two `@Test` functions, meaning the `let value: UUID` properties of all trait instances would be the same. (Again, this is all assuming `isRecursive` is `true`.)

> [@pavm035](#):
>
> - Even though `provideScope()` is called per test, all tests access the same stored properties?

`provideScope()` will be called on the instance of the trait applied to, or inherited by, the relevant test. One way to think about this scenario is that there are 3 total copies of `MyTrait`, and they each have the same value for the `let value: UUID` property.

> [@pavm035](#):
>
> If so, would the best practice be to:
> 
> - Avoid storing per-test data in suite-level trait properties?

I would generally agree with this. Although note that in your example, `MyTrait` is a struct, and value semantics will generally prevent you from sharing data in the way you might be thinking.

> [@pavm035](#):
>
> - Use helper methods or closures to generate fresh values inside `provideScope()`?

I'm not certain what kind of fresh data you mean. Perhaps it would help to explain what your overall goal is.

Hope that helps!  
Stuart

---

<div class="post-metadata">

**Author:** ![pavm035](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/pavm035/32/18274_2.png) [@pavm035](https://forums.swift.org/u/pavm035)\
**Post date:** [April 14, 2025, 12:16am UTC](https://forums.swift.org/t/are-trait-stored-properties-shared-across-all-tests-when-attached-at-the-suite-level/79244/3 "2025-04-14T00:16:19Z")

</div>

Hi @smontgomery,

Thanks for the quick and detailed feedback — very helpful!

> As written, this code doesn't compile because `MyTrait` doesn't conform to `SuiteTrait`. Only trait types which conform to `SuiteTrait` may be applied to suites via the `@Suite(...)` attribute. I'll assume in your "real" code you did have this conformance, though.

Yes, you're absolutely right — I forgot to include the `SuiteTrait` conformance in the example, but I do have it in the actual code.

> I would generally agree with this. Although note that in your example, `MyTrait` is a struct, and value semantics will generally prevent you from sharing data in the way you might be thinking.

Understood. But as you mentioned, tests inside the suite inherit a copy of the `MyTrait` instance from the suite. So if we were to include a **mutable** property in `MyTrait` (which I didn’t show in the example), it could lead to data races or unexpected shared state — especially in concurrent scenarios.

> I'm not certain what kind of fresh data you mean. Perhaps it would help to explain what your overall goal is.

Sorry for not being clear — by "fresh data", I meant that instead of storing test dependencies as properties inside `MyTrait`, I can pass in **closures** that generate new instances per test.

For example:

```swift
struct MyTrait: TestTrait, SuiteTrait, TestScoping {
    let makeMockAPI: @Sendable () -> MockAPI

    func provideScope(...) async throws {
        let api = makeMockAPI() // ← fresh instance for each test
        ...
    }

    var isRecursive: Bool = true
}

```

This approach ensures isolation and avoids shared state, while still allowing common setup at the suite level.

My overall goal is to simplify test setup by providing **common mock dependencies** (e.g., mock services, configurations) at the suite or sub-suite level using a shared trait. At the same time, I’d like to allow **individual tests** to override those dependencies when needed by attaching their own customized version of `MyTrait`. This mirrors the pattern we’ve used in Quick/Nimble with `beforeSuite`, `beforeEach`, and so on, and we’re now looking to migrate those test cases to Swift Testing.

If there are any recommended best practices or alternative approaches for handling this pattern — especially around trait composition, overriding, or scoped setup — I’d really appreciate any guidance.

Thanks again for the clarification — this really helped solidify my understanding of how traits are constructed and propagated!
