Advanced Test Customization with Traits

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

Advanced Test Customization with Traits

We have already encountered traits when using .tags() to categorize tests. However, the trait system in Swift Testing is far more extensive. Traits are the universal mechanism for annotating tests and suites to customize their runtime behavior, add metadata, and control their execution conditions. They are passed as arguments to the @Test or @Suite macros.

Conditional Execution

Not all tests should be run all the time. Some tests might be for a feature that is currently disabled by a feature flag, while others might be temporarily failing due to a known bug or an incomplete backend. Traits provide an elegant way to manage these scenarios.

struct FeatureFlags {
  static var isNewCommentingSystemEnabled = false
}

@Test(
  "Post a comment with an attachment",
  .enabled(if: FeatureFlags.isNewCommentingSystemEnabled)
)
func testCommentWithAttachment() {
  // This test will be skipped if the feature flag is false.
}
@Test(
  "Test video transcoding",
  .disabled("This test is flaky and is being investigated.")
)
func testVideoTranscoding() {
  // This test will be marked as "skipped" in the test run.
}

Performance and Stability

In automated testing environments, it is crucial to prevent tests from getting stuck and running indefinitely. A test that hangs can block an entire CI/CD pipeline.

@Test(
  "Process large dataset",
  .timeLimit(.seconds(30))
)
func testLargeDataProcessing() async throws {
  // If this function takes longer than 30 seconds, the test will fail.
}

Associating Metadata

To improve traceability and context, especially in large teams, it is helpful to link tests directly to related items in external systems like bug trackers.

@Test(
  "Test currency conversion for rare currencies",
  .disabled("Fails due to rounding error in backend API."),
  .bug(id: "FIN-472", url: "https://your-tracker.com/FIN-472")
)
func testRareCurrencyConversion() {
  //...
}
Trait Purpose Example Usage
.tags(...) Categorize tests with semantic labels. .tags(.ui,.critical)
.enabled(if:...) Run test only if a condition is true. .enabled(if: FeatureFlags.isNewCheckoutEnabled)
.disabled(...) Skip a test, with an optional reason. .disabled("Backend endpoint not ready")
.timeLimit(...) Fail the test if it exceeds a duration. .timeLimit(.minutes(1))
.bug(...) Link the test to a bug report. .bug(id: "FB-90210")
.serialized Force tests in a suite to run one by one. @Suite(.serialized)
See forum comments
Download course materials from Github
Previous: Grouping Tests with @Suite Next: Parameterized Tests