12
12
Many projects want to migrate from XCTest to Swift Testing, and may be in an
13
13
intermediate state where test helpers written using XCTest API are called from
14
14
Swift Testing. Today, the Swift Testing and XCTest libraries stand mostly
15
- independently, which means an ` XCTAssert ` failure in a Swift Testing test is
16
- silently ignored. To address this, we formally declare a set of interoperability
17
- principles and propose changes to the handling of specific APIs that will enable
18
- users to migrate with confidence.
15
+ independently, which means an [ ` XCTAssert ` ] [ XCTest assertions ] failure in a
16
+ Swift Testing test or an [ ` #expect ` ] [ Swift Testing expectations ] failure in an
17
+ XCTest test is silently ignored. To address this, we formally declare a set of
18
+ interoperability principles and propose changes to the handling of specific APIs
19
+ that will enable users to migrate with confidence.
19
20
20
21
## Motivation
21
22
@@ -44,19 +45,21 @@ class FooTests: XCTestCase {
44
45
}
45
46
```
46
47
47
- Generally, we get into trouble today when ALL the following conditions are met:
48
+ Generally, you encounter the above limitation with testing APIs when _ all_ the
49
+ following conditions are met:
48
50
49
51
- You call XCTest API in a Swift Testing test, or call Swift Testing API in a
50
52
XCTest test,
51
53
- The API doesn't function as expected in some or all cases, and
52
54
- You get no notice at build time or runtime about the malfunction
53
55
54
56
For the remainder of this proposal, we’ll describe test APIs which exhibit this
55
- problem as ** lossy without interop** .
57
+ limitation as ** lossy without interop** .
56
58
57
- This problem risks regressing test coverage for projects which migrate to Swift
58
- Testing. Furthermore, projects that have switched completely to Swift Testing
59
- may want to go and ensure they don't inadvertently add XCTest API.
59
+ You could regress test coverage if you migrate to Swift Testing without
60
+ replacing usage of lossy without interop test APIs. Furthermore, you may want to
61
+ ensure you don't inadvertently introduce new XCTest API after completing your
62
+ Swift Testing migration.
60
63
61
64
## Proposed solution
62
65
@@ -106,7 +109,7 @@ We also propose highlighting usage of above XCTest APIs in Swift Testing:
106
109
107
110
- ** Report [ runtime warning issues] [ ] ** for XCTest API usage in Swift Testing.
108
111
This ** applies to both assertion failures _ and successes_ ** ! This notifies you
109
- about opportunities to modernise even if your tests currently pass.
112
+ about opportunities to modernize even if your tests currently pass.
110
113
111
114
- Opt-in ** strict interop mode** , where XCTest API usage will result in
112
115
` fatalError("Usage of XCTest API in a Swift Testing context is unsupported") ` .
@@ -123,7 +126,8 @@ Here are some concrete examples:
123
126
124
127
We propose supporting the following Swift Testing APIs in XCTest:
125
128
126
- - ` #expect ` and ` #require `
129
+ - [ ` #expect ` and ` #require ` ] [ Swift Testing expectations ]
130
+ - Includes [ ` #expect(throws:) ` ] [ testing for errors ]
127
131
- Includes [ exit testing] [ ]
128
132
- ` withKnownIssue ` : marking an XCTest issue in this way will generate a runtime
129
133
warning issue. In strict interop mode, this becomes a ` fatalError ` .
@@ -144,7 +148,7 @@ is analogous to `XCTSkip`. If that pitch were accepted, this proposal would
144
148
support interop of the new API with XCTest.
145
149
146
150
On the other hand, [ traits] [ ] are a powerful Swift Testing feature which is not
147
- related to any functionality in XCTest. Therefore, there would be
151
+ related to any functionality in XCTest. Therefore, there would not be
148
152
interoperability for traits under this proposal.
149
153
150
154
Here are some concrete examples:
@@ -174,21 +178,18 @@ Here are some concrete examples:
174
178
Configure the interoperability mode when running tests using the
175
179
` SWIFT_TESTING_XCTEST_INTEROP_MODE ` environment variable:
176
180
177
- | Interop Mode | Issue behaviour across framework boundary | ` SWIFT_TESTING_XCTEST_INTEROP_MODE ` |
181
+ | Interop Mode | Issue behavior across framework boundary | ` SWIFT_TESTING_XCTEST_INTEROP_MODE ` |
178
182
| ------------ | -------------------------------------------------------------------------- | ---------------------------------------------- |
179
- | Advisory | XCTest API: ⚠️ Runtime Warning Issue. All Issues: ⚠️ Runtime Warning Issue | ` warning-only ` |
183
+ | Advisory | XCTest API: ⚠️ Runtime Warning Issue. All Issues: ⚠️ Runtime Warning Issue | ` advisory ` |
180
184
| Permissive | XCTest API: ⚠️ Runtime Warning Issue. All Issues: ❌ Test Failure | ` permissive ` , or empty value, or invalid value |
181
185
| Strict | XCTest API: 💥 ` fatalError ` . Swift Testing API: ❌ Test Failure | ` strict ` |
182
186
183
- ### Phased Rollout
187
+ ## Source compatibility
184
188
185
189
When interoperability is first available, "permissive" will be the default
186
- interop mode enabled for new projects. In a future release, "strict" will become
187
- the default interop mode.
188
-
189
- ## Source compatibility
190
+ interop mode enabled for new projects.
190
191
191
- As the main goal of interoperability is to change behaviour , this proposal will
192
+ As the main goal of interoperability is to change behavior , this proposal will
192
193
lead to situations where previously "passing" test code now starts showing
193
194
failures. We believe this should be a net positive if it can highlight actual
194
195
bugs you would have missed previously.
@@ -199,31 +200,34 @@ interoperability.
199
200
200
201
## Integration with supporting tools
201
202
202
- Interoperability will be first available in future toolchain version,
203
- hypothetically named ` 6.X ` , where permissive interop mode will be enabled for
204
- projects. After that, a ` 7.Y ` release would make strict interop mode the
205
- default.
206
-
207
203
- Swift packages: ` swift-tools-version ` declared in Package.swift will be used
208
204
to determine interop mode, regardless of the toolchain used to run tests.
205
+ Specifically, it will use the default interop mode associated with that
206
+ toolchain version ("permissive" for the initial release version).
207
+
208
+ We will work with the Swift Package Manager maintainers and the Ecosystem
209
+ Steering Group to make appropriate changes in other parts of the toolchain.
209
210
210
- - Otherwise, installed toolchain version will be used to determine interop mode.
211
+ - Otherwise, the default interop mode associated with the installed toolchain
212
+ version will be used to determine interop mode.
211
213
212
214
- Any project can use ` SWIFT_TESTING_XCTEST_INTEROP_MODE ` to override interop
213
- mode at runtime, provided they are on toolchain version ` 6.X ` or newer
215
+ mode at runtime.
214
216
215
217
## Future directions
216
218
217
219
There's still more we can do to make it easier to migrate from XCTest to Swift
218
220
Testing:
219
221
222
+ - In a future release, we would consider making strict interop mode the default.
223
+
220
224
- Provide fixups at compile-time to replace usage of XCTest API with the
221
225
corresponding Swift Testing API, e.g. replace ` XCTAssert ` with ` #expect ` .
222
226
However, this would require introspection of the test body to look for XCTest
223
227
API usage, which would be challenging to do completely and find usages of this
224
228
API within helper methods.
225
229
226
- - After new API is added to Swift Testing in future, will need to evaluate for
230
+ - When new API is added to Swift Testing, we will need to evaluate it for
227
231
interoperability with XCTest.
228
232
229
233
## Alternatives considered
@@ -263,16 +267,16 @@ that we want users to migrate to Swift Testing.
263
267
However, we are especially sensitive to use cases that depend upon the currently
264
268
lossy without interop APIs. With strict interop mode, the test process will
265
269
crash on the first instance of XCTest API usage in Swift Testing, completely
266
- halting testing. In this same scenario, the default permissive interop mode
267
- would record a runtime warning issue and continue the remaining test, which we
268
- believe strikes a better balance between notifying users yet not being totally
269
- disruptive to the testing flow.
270
+ halting testing. In this same scenario, the proposed default permissive interop
271
+ mode would record a runtime warning issue and continue the remaining test, which
272
+ we believe strikes a better balance between notifying users yet not being
273
+ totally disruptive to the testing flow.
270
274
271
275
### Alternative methods to control interop mode
272
276
273
277
- ** Build setting:** e.g. a new ` SwiftSetting ` that can be included in
274
- Package.swift or an Xcode project . A project could then configure their test
275
- targets to have a non-default interop mode.
278
+ Package.swift. A project could then configure their test targets to have a
279
+ non-default interop mode.
276
280
277
281
However, interop is a runtime concept, and would be difficult or at least
278
282
non-idiomatic to modify with a build setting.
@@ -291,12 +295,17 @@ disruptive to the testing flow.
291
295
Thanks to Stuart Montgomery, Jonathan Grynspan, and Brian Croom for feedback on
292
296
the proposal.
293
297
298
+ <!-- XCTest -->
294
299
[ XCTest assertions ] : https://developer.apple.com/documentation/xctest/equality-and-inequality-assertions
295
300
[ XCTest attachments ] : https://developer.apple.com/documentation/xctest/adding-attachments-to-tests-activities-and-issues
296
301
[ unconditional failure ] : https://developer.apple.com/documentation/xctest/unconditional-test-failures
297
- [ runtime warning issues ] : https://github.com/swiftlang/swift-evolution/blob/main/proposals/testing/0013-issue-severity-warning.md
298
302
[ expected failures ] : https://developer.apple.com/documentation/xctest/expected-failures
303
+ <!-- Swift Testing -->
304
+ [ Swift Testing expectations ] : https://developer.apple.com/documentation/testing/expectations
305
+ [ Testing for errors ] : https://developer.apple.com/documentation/testing/testing-for-errors-in-swift-code
306
+ [ exit testing ] : https://developer.apple.com/documentation/testing/exit-testing
299
307
[ issue handling traits ] : https://developer.apple.com/documentation/testing/issuehandlingtrait
308
+ [ traits ] : https://developer.apple.com/documentation/testing/traits
309
+ <!-- Misc -->
310
+ [ runtime warning issues ] : https://github.com/swiftlang/swift-evolution/blob/main/proposals/testing/0013-issue-severity-warning.md
300
311
[ test cancellation ] : https://forums.swift.org/t/pitch-test-cancellation/81847
301
- [ traits ] : https://swiftpackageindex.com/swiftlang/swift-testing/main/documentation/testing/traits
302
- [ exit testing ] : https://developer.apple.com/documentation/testing/exit-testing
0 commit comments