ADR-17: Swift Testing Framework Support
🇰🇷 한국어 버전
| Date | Author | Repos |
|---|---|---|
| 2026-01-04 | @specvital | core |
Context
Problem Statement
During validation of major Swift repositories (e.g., Alamofire with 40K+ GitHub stars), Swift Testing tests were not being detected. The existing XCTest parser only recognizes:
func testXxx()naming convention- Classes extending
XCTestCase
Apple introduced Swift Testing at WWDC 2024 (Swift 6 / Xcode 16) with fundamentally different patterns:
| Pattern | XCTest | Swift Testing |
|---|---|---|
| Test declaration | func testXxx() | @Test attribute |
| Suite grouping | XCTestCase subclass | @Suite (optional, implicit for @Test) |
| Skip mechanism | XCTSkip() runtime | @Test(.disabled) compile-time trait |
| Assertions | XCTAssert* | #expect(), #require() |
| Type support | Classes only | Struct, Actor, Class |
Impact
- 57 tests undetected in Alamofire repository
- Growing adoption of Swift Testing in iOS/macOS projects
- Apple's official recommendation for new Swift tests
Requirements
- Detect Swift Testing tests via
@Testand@Suiteattributes - Recognize skip status from
@Test(.disabled)trait - Support async test functions
- Share AST utilities with XCTest via
swiftastmodule - Maintain backward compatibility with existing XCTest detection
Decision
Implement Swift Testing as a separate framework with PrioritySpecialized detection.
The swifttesting framework is registered as an independent definition alongside xctest, sharing the swiftast module for common Swift AST utilities.
Detection Strategy
Priority-based early-return (per ADR-04):
- Import detection (highest):
import Testingtriggers Swift Testing parser - Attribute detection:
@Test,@Suitepresence confirms framework - Content patterns:
#expect(),#require()as supporting signals
Parser Implementation
func NewDefinition() *framework.Definition {
return &framework.Definition{
Name: "swifttesting",
Languages: []domain.Language{domain.LanguageSwift},
Matchers: []framework.Matcher{
matchers.NewImportMatcher("Testing"),
&SwiftTestingContentMatcher{}, // @Test, @Suite, #expect
},
Parser: &SwiftTestingParser{},
Priority: framework.PrioritySpecialized, // 200
}
}Skip Detection
@Test(.disabled) trait maps to TestStatusSkipped:
// "@Test(.disabled)" or "@Test(.disabled(\"reason\"))"
if hasDisabledTrait(annotation) {
return domain.TestStatusSkipped
}Async Support
Content scan for async keyword in function signature:
@Test func fetchData() async throws { ... }Options Considered
Option A: Separate Framework Strategy (Selected)
Create distinct swifttesting framework definition with PrioritySpecialized.
Pros:
- Framework isolation enables independent evolution
- Clean detection via
import Testing - Native support for Swift Testing traits (
@Test(.disabled)) - Shares
swiftastmodule for code reuse - Follows Unified Framework Definition pattern (ADR-06)
Cons:
- Two Swift framework definitions to maintain
- Potential detection overlap in mixed files
Option B: Extend Existing XCTest Parser
Add Swift Testing patterns within XCTest definition.
Pros:
- Single Swift framework definition
- Shared maintenance scope
Cons:
- Violates single-responsibility principle
- Complex internal branching for fundamentally different patterns
- Bug fixes could cascade across both frameworks
- Apple explicitly positions these as distinct frameworks
Option C: Universal Swift Parser
Single Swift parser with sub-framework routing.
Pros:
- Maximum code sharing
- Single entry point for Swift
Cons:
- Over-generalization risk
- Complex internal routing
- Framework-specific edge cases leak across boundaries
Option D: Pattern-Based Detection Only
Regex-based detection without AST parsing.
Pros:
- Lightweight implementation
- Fast execution
Cons:
- Cannot extract parameterized test names
- Cannot detect async functions properly
- Cannot parse nested suites
- Insufficient for production accuracy requirements
Consequences
Positive
Framework Isolation
- Swift Testing evolves independently from XCTest
- No regression risk when updating one parser
- Clear ownership and responsibility per framework
Accurate Detection
import Testingprovides highest-reliability detection signal@Test(.disabled)natively maps to skip status- Async function detection via content scan
Code Reuse via Shared Modules
swiftastmodule provides common AST utilities- Bug fixes in
swiftastbenefit both parsers - Follows Shared Parser Modules pattern (ADR-08)
Future-Proof Architecture
- Extensible to support additional traits (
@Test(.bug()),@Test(.tags())) - Ready for parameterized tests (
@Test(arguments:)) - Aligned with Apple's framework direction
- Extensible to support additional traits (
Consistent with Existing ADRs
- Unified Framework Definition (ADR-06)
- Early-Return Framework Detection (ADR-04)
- Shared Parser Modules (ADR-08)
Negative
Dual Framework Maintenance
- Two separate definition files for Swift
- Mitigation: Shared
swiftastmodule minimizes duplication
Mixed File Detection
- Files using both XCTest and Swift Testing (Apple-supported scenario)
- Mitigation:
PrioritySpecializedensures Swift Testing detected first; explicit import wins
Initial Development Investment
- New definition.go, matchers, and parser implementation
- Mitigation: Leverage existing
swiftastmodule; follow established patterns
References
- Commit 161b650: feat(swift-testing): add Apple Swift Testing framework support
- Issue #95: Add Apple Swift Testing framework support
- ADR-04: Early-Return Framework Detection
- ADR-06: Unified Framework Definition
- ADR-08: Shared Parser Modules
- Swift Testing - Apple Developer
- Meet Swift Testing - WWDC24
