1
- # Interoperability between Swift Testing and XCTest
1
+ # Targeted Interoperability between Swift Testing and XCTest
2
2
3
3
- Proposal: [ ST-NNNN] ( NNNN-xctest-interoperability.md )
4
4
- Authors: [ Jerry Chen] ( https://github.com/jerryjrchen )
@@ -51,18 +51,15 @@ Generally, we get into trouble today when ALL the following conditions are met:
51
51
- You call XCTest API in a Swift Testing test, or call Swift Testing API in a
52
52
XCTest test
53
53
- 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
58
55
59
56
For the remainder of this proposal, we’ll describe tests which exhibit this
60
57
problem as ** lossy without interop** .
61
58
62
59
If you've switched completely to Swift Testing and don't expect to use XCTest in
63
60
the 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.
66
63
67
64
## Proposed solution
68
65
@@ -90,7 +87,7 @@ We propose supporting the following XCTest APIs in Swift Testing:
90
87
91
88
- Assertions: ` XCTAssert* ` and [ unconditional failure] [ ] ` XCTFail `
92
89
- [ 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.
94
91
- ` XCTAttachment `
95
92
- [ Issue handling traits] [ ] : we will make our best effort to translate issues
96
93
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:
104
101
105
102
- ** Report [ runtime warning issues] [ ] ** for XCTest API usage in Swift Testing.
106
103
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.
108
105
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")`.
110
109
111
110
Here are some concrete examples:
112
111
113
112
| When running a Swift Testing test... | Current | Proposed (default) | Proposed (strict) |
114
113
| ------------------------------------ | --------------- | -------------------------------------------- | ----------------- |
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 ` |
117
116
| ` throw XCTSkip ` is a ... | ❌ Test Failure | ❌ Test Failure | ❌ Test Failure |
118
117
119
118
### Limited support for Swift Testing APIs in XCTest
@@ -122,8 +121,8 @@ We propose supporting the following Swift Testing APIs in XCTest:
122
121
123
122
- ` #expect ` and ` #require `
124
123
- 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 ` .
127
126
- Attachments
128
127
- [ Test cancellation] [ ] (links to pitch)
129
128
@@ -136,12 +135,12 @@ Testing at your own pace.
136
135
Present and future Swift Testing APIs will be supported in XCTest if the
137
136
XCTest API _ already_ provides similar functionality.
138
137
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 ` .
141
140
142
141
- On the other hand, [ Traits] [ ] are a powerful Swift Testing feature, and
143
142
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**
145
144
because XCTest doesn't have existing “tag-like” behaviour to map onto.
146
145
147
146
Here are some concrete examples:
@@ -150,38 +149,33 @@ Here are some concrete examples:
150
149
| -------------------------------------------- | --------------- | ------------------------ | ----------------- |
151
150
| ` #expect ` failure is a ... | ‼️ No-op | ❌ Test Failure | ❌ Test Failure |
152
151
| ` #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 ` |
154
153
155
154
### Interoperability Modes
156
155
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:
160
158
161
159
- ** Warning-only** : This is for projects which do not want to see new test
162
160
failures surfaced due to interoperability.
163
161
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
-
171
162
- ** Strict** : Warning issues included in the default mode can be easily
172
163
overlooked, especially in CI. The strict mode guarantees that no XCTest API
173
164
usage occurs when running Swift Testing tests by turning those warnings into a
174
- runtime crash .
165
+ ` fatalError ` .
175
166
176
167
Configure 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 ` |
178
175
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-->
185
179
186
180
### Phased Rollout
187
181
@@ -196,15 +190,15 @@ lead to situations where previously "passing" test code now starts showing
196
190
failures. We believe this should be a net positive if it can highlight actual
197
191
bugs you would have missed previously.
198
192
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
200
194
the current behaviour. Refer to the "Interoperability Modes" section for a full list
201
195
of options.
202
196
203
197
## Integration with supporting tools
204
198
205
199
Interoperability will be first available in future toolchain version,
206
200
hypothetically 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
208
202
default.
209
203
210
204
- Swift Package Manager projects: ` swift-tools-version ` declared in
@@ -214,8 +208,8 @@ default.
214
208
- Xcode projects: Installed toolchain version will be used to determine interop
215
209
mode.
216
210
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
219
213
220
214
## Future directions
221
215
@@ -228,10 +222,9 @@ Testing:
228
222
API usage, which would be challenging to do completely and find usages of this
229
223
API within helper methods.
230
224
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.
235
228
236
229
## Alternatives considered
237
230
@@ -249,6 +242,18 @@ helping users catch more bugs are too important to pass up. We've also included
249
242
a plan to increase the strictness of the interoperability mode over time, which
250
243
should make it clear that this is not intended to be a permanent measure.
251
244
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
+
252
257
### Strict interop mode as the default
253
258
254
259
We 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
259
264
lossy without interop APIs, and decided to prioritise the current default as a
260
265
good balance between notifying users yet not breaking existing test suites.
261
266
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
+
262
285
## Acknowledgments
263
286
264
287
Thanks to Stuart Montgomery, Jonathan Grynspan, and Brian Croom for feedback on
0 commit comments