1- # Interoperability between Swift Testing and XCTest
1+ # Targeted Interoperability between Swift Testing and XCTest
22
33- Proposal: [ ST-NNNN] ( NNNN-xctest-interoperability.md )
44- Authors: [ Jerry Chen] ( https://github.com/jerryjrchen )
@@ -51,18 +51,15 @@ Generally, we get into trouble today when ALL the following conditions are met:
5151- You call XCTest API in a Swift Testing test, or call Swift Testing API in a
5252 XCTest test
5353- The API doesn't function as expected in some or all cases, and
54- - You get no notice at build or runtime about the malfunction
55-
56- Example: calling ` XCTAssertEqual(x, y) ` in a Swift Testing test: if x does not
57- equal y, it should report a failure but does nothing instead.
54+ - You get no notice at build time or runtime about the malfunction
5855
5956For the remainder of this proposal, we’ll describe tests which exhibit this
6057problem as ** lossy without interop** .
6158
6259If you've switched completely to Swift Testing and don't expect to use XCTest in
6360the future, this proposal includes a mechanism to ** prevent you from
64- inadvertently introducing XCTest APIs to your project, including via a testing
65- library.**
61+ inadvertently introducing XCTest APIs to your project** , including via a testing
62+ library.
6663
6764## Proposed solution
6865
@@ -90,7 +87,7 @@ We propose supporting the following XCTest APIs in Swift Testing:
9087
9188- Assertions: ` XCTAssert* ` and [ unconditional failure] [ ] ` XCTFail `
9289- [ Expected failures] [ ] , such as ` XCTExpectFailure ` : marking a Swift Testing
93- issue in this way will generate a runtime issue.
90+ issue in this way will generate a runtime warning issue.
9491- ` XCTAttachment `
9592- [ Issue handling traits] [ ] : we will make our best effort to translate issues
9693 from XCTest to Swift Testing. Note that there are certain issue kinds that are
@@ -104,16 +101,18 @@ We also propose highlighting usage of above XCTest APIs in Swift Testing:
104101
105102- ** Report [ runtime warning issues] [ ] ** for XCTest API usage in Swift Testing.
106103 This ** applies to assertion successes AND failures** ! We want to make sure you
107- can identify opportunities to modernise even if your tests currently all pass.
104+ can identify opportunities to modernise even if your tests currently pass.
108105
109- - Opt-in ** strict interop mode** , which will trigger a crash instead.
106+ - Opt-in ** strict interop mode** , where XCTest API usage will result in
107+ `fatalError("Usage of XCTest API in a Swift Testing context is not
108+ supported")`.
110109
111110Here are some concrete examples:
112111
113112| When running a Swift Testing test... | Current | Proposed (default) | Proposed (strict) |
114113| ------------------------------------ | --------------- | -------------------------------------------- | ----------------- |
115- | ` XCTAssert ` failure is a ... | ‼️ No-op | ❌ Test Failure and ⚠️ Runtime Warning Issue | 💥 Crash |
116- | ` XCTAssert ` success is a ... | No-op | ⚠️ Runtime Warning Issue | 💥 Crash |
114+ | ` XCTAssert ` failure is a ... | ‼️ No-op | ❌ Test Failure and ⚠️ Runtime Warning Issue | 💥 ` fatalError ` |
115+ | ` XCTAssert ` success is a ... | No-op | ⚠️ Runtime Warning Issue | 💥 ` fatalError ` |
117116| ` throw XCTSkip ` is a ... | ❌ Test Failure | ❌ Test Failure | ❌ Test Failure |
118117
119118### Limited support for Swift Testing APIs in XCTest
@@ -122,8 +121,8 @@ We propose supporting the following Swift Testing APIs in XCTest:
122121
123122- ` #expect ` and ` #require `
124123 - Includes [ exit testing] [ ]
125- - ` withKnownIssue ` : when this suppresses ` XCTAssert ` failures, it will still
126- show a runtime warning issue .
124+ - ` withKnownIssue ` : marking an XCTest issue in this way will generate a runtime
125+ warning issue. In strict interop mode, this becomes a ` fatalError ` .
127126- Attachments
128127- [ Test cancellation] [ ] (links to pitch)
129128
@@ -136,12 +135,12 @@ Testing at your own pace.
136135Present and future Swift Testing APIs will be supported in XCTest if the
137136XCTest API _ already_ provides similar functionality.
138137
139- - For example, we plan on supporting the proposed Swift Testing [ test
140- cancellation ] [ ] feature in XCTest since it is analogous to ` XCTSkip `
138+ - For example, we support the proposed Swift Testing [ test cancellation ] [ ]
139+ feature in XCTest since it is analogous to ` XCTSkip ` .
141140
142141- On the other hand, [ Traits] [ ] are a powerful Swift Testing feature, and
143142 include the ability to [ add tags] [ tags ] to organise tests. Even though XCTest
144- does not interact with tags, this is beyond the scope of interoperability
143+ does not interact with tags, ** this is beyond the scope of interoperability**
145144 because XCTest doesn't have existing “tag-like” behaviour to map onto.
146145
147146Here are some concrete examples:
@@ -150,38 +149,33 @@ Here are some concrete examples:
150149| -------------------------------------------- | --------------- | ------------------------ | ----------------- |
151150| ` #expect ` failure is a ... | ‼️ No-op | ❌ Test Failure | ❌ Test Failure |
152151| ` #expect ` success is a ... | No-op | No-op | No-op |
153- | ` withKnownIssue ` wrapping ` XCTFail ` is a ... | ❌ Test Failure | ⚠️ Runtime Warning Issue | 💥 Crash |
152+ | ` withKnownIssue ` wrapping ` XCTFail ` is a ... | ❌ Test Failure | ⚠️ Runtime Warning Issue | 💥 ` fatalError ` |
154153
155154### Interoperability Modes
156155
157- The default interoperability surfaces test failures that were previously
158- ignored. We include two more permissible interoperability modes to avoid
159- breaking projects that are dependent on this pre-interop behaviour.
156+ The default interoperability mode surfaces test failures that were previously
157+ ignored. We also include two alternative interoperability modes:
160158
161159- ** Warning-only** : This is for projects which do not want to see new test
162160 failures surfaced due to interoperability.
163161
164- - ** None** : Some projects may additionally have issue handling trait that
165- promote warnings to errors, which means that warning-only mode could still
166- cause test failures.
167-
168- For projects that want to bolster their Swift Testing adoption, there is also an
169- opt-in strict interop mode.
170-
171162- ** Strict** : Warning issues included in the default mode can be easily
172163 overlooked, especially in CI. The strict mode guarantees that no XCTest API
173164 usage occurs when running Swift Testing tests by turning those warnings into a
174- runtime crash .
165+ ` fatalError ` .
175166
176167Configure the interoperability mode when running tests using the
177- ` SWT_XCTEST_INTEROP_MODE ` environment variable:
168+ ` SWIFT_TESTING_XCTEST_INTEROP_MODE ` environment variable:
169+
170+ | Interop Mode | Issue behaviour across framework boundary | ` SWIFT_TESTING_XCTEST_INTEROP_MODE ` |
171+ | ------------ | ----------------------------------------------------------------- | ------------------------------------------- |
172+ | Warning-only | ⚠️ Runtime Warning Issue for XCTest API usage | ` warning ` |
173+ | Default | ❌ Test Failure and ⚠️ Runtime Warning Issue for XCTest API usage | ` default ` , or empty value, or invalid value |
174+ | Strict | 💥 ` fatalError ` for XCTest API usage | ` strict ` |
178175
179- | Interop Mode | Issue behaviour across framework boundary | ` SWT_XCTEST_INTEROP_MODE ` |
180- | ------------ | -------------------------------------------- | ------------------------------------------- |
181- | Off | ‼️ No-op (status quo) | ` off ` |
182- | Warning-only | ⚠️ Runtime Warning Issue | ` warning ` |
183- | Default | ❌ Test Failure and ⚠️ Runtime Warning Issue | ` default ` , or empty value, or invalid value |
184- | Strict | 💥 Crash | ` strict ` |
176+ <!-- TODO: alternative name besides strict. It should reflect that, it does
177+ still have interop for SWT API in XCTest, but a hard failure going the other way
178+ around-->
185179
186180### Phased Rollout
187181
@@ -196,15 +190,15 @@ lead to situations where previously "passing" test code now starts showing
196190failures. We believe this should be a net positive if it can highlight actual
197191bugs you would have missed previously.
198192
199- You can use ` SWT_XCTEST_INTEROP_MODE =off` in the short-term to revert back to
193+ You can use ` SWIFT_TESTING_XCTEST_INTEROP_MODE =off` in the short-term to revert back to
200194the current behaviour. Refer to the "Interoperability Modes" section for a full list
201195of options.
202196
203197## Integration with supporting tools
204198
205199Interoperability will be first available in future toolchain version,
206200hypothetically named ` 6.X ` , where default interop mode will be enabled for
207- projects. After that, a ` 6 .Y` release would make strict interop mode the
201+ projects. After that, a ` 7 .Y` release would make strict interop mode the
208202default.
209203
210204- Swift Package Manager projects: ` swift-tools-version ` declared in
@@ -214,8 +208,8 @@ default.
214208- Xcode projects: Installed toolchain version will be used to determine interop
215209 mode.
216210
217- - Any project can use ` SWT_XCTEST_INTEROP_MODE ` to override interop mode at
218- runtime, provided they are on toolchain version ` 6.X ` or newer
211+ - Any project can use ` SWIFT_TESTING_XCTEST_INTEROP_MODE ` to override interop
212+ mode at runtime, provided they are on toolchain version ` 6.X ` or newer
219213
220214## Future directions
221215
@@ -228,10 +222,9 @@ Testing:
228222 API usage, which would be challenging to do completely and find usages of this
229223 API within helper methods.
230224
231- - After new API added to SWT in future, will need to evaluate for
232- interoperability with XCTest until strict mode is the default. "strict" is
233- kind of saying "from this point forward, no new interop will be added" for new
234- SWT features.
225+ - After new API is added to Swift Testing in future, will need to evaluate for
226+ interoperability with XCTest. Once strict mode is the default, we will no
227+ longer include interoperability for new Swift Testing features.
235228
236229## Alternatives considered
237230
@@ -249,6 +242,18 @@ helping users catch more bugs are too important to pass up. We've also included
249242a plan to increase the strictness of the interoperability mode over time, which
250243should make it clear that this is not intended to be a permanent measure.
251244
245+ ### Opt-out of interoperability
246+
247+ In a similar vein, we considered ` SWIFT_TESTING_XCTEST_INTEROP_MODE=off ` as a
248+ way to completely turn off interoperability. Some projects may additionally have
249+ issue handling trait that promote warnings to errors, which means that
250+ warning-only mode could still cause test failures.
251+
252+ However, in the scenario above, we think users who set up tests to elevate
253+ warnings as errors would be interested in increased visibility of testing issues
254+ surfaced by interop. We're open to feedback about other scenarios where a
255+ "interop off" mode would be preferred.
256+
252257### Strict interop mode as the default
253258
254259We believe that for projects using only Swift Testing, strict interop mode is
@@ -259,6 +264,24 @@ However, we are especially sensitive to use cases that depend upon the currently
259264lossy without interop APIs, and decided to prioritise the current default as a
260265good balance between notifying users yet not breaking existing test suites.
261266
267+ ### Alternative methods to control interop mode
268+
269+ - ** Build setting:** e.g. a new ` SwiftSetting ` that can be included in
270+ Package.swift or an Xcode project. A project could then configure their test
271+ targets to have a non-default interop mode.
272+
273+ However, interop is a runtime concept, and would be difficult or at least
274+ non-idiomatic to modify with a build setting.
275+
276+ - ** CLI option through SwiftPM:**
277+
278+ ```
279+ swift test --interop-mode=warning-only
280+ ```
281+
282+ This could be offered in addition to the proposed environment variable option,
283+ although it would be unclear which one should take precedence.
284+
262285## Acknowledgments
263286
264287Thanks to Stuart Montgomery, Jonathan Grynspan, and Brian Croom for feedback on
0 commit comments