6
6
* Implementation: [ swiftlang/swift-testing #733 ] ( https://github.com/swiftlang/swift-testing/pull/733 ) , [ swiftlang/swift-testing #86 ] ( https://github.com/swiftlang/swift-testing/pull/86 )
7
7
* Review: ([ pitch] ( https://forums.swift.org/... ) )
8
8
9
+ ### Revision history
10
+
11
+ * ** v1** : Initial pitch.
12
+ * ** v2** : Dropped 'Custom' prefix from the proposed API names (although kept the
13
+ word in certain documentation passages where it clarified behavior).
14
+
9
15
## Introduction
10
16
11
17
This introduces API which enables a custom ` Trait ` -conforming type to customize
@@ -190,21 +196,19 @@ these scoped access calls to only the traits which require it.
190
196
191
197
I propose the following new APIs:
192
198
193
- - A new protocol ` CustomTestExecuting ` with a single required ` execute(...) `
194
- method. This will be called to run a test, and allows the conforming type to
195
- perform custom logic before or after.
196
- - A new property ` customTestExecutor ` on the ` Trait ` protocol whose type is an
197
- ` Optional ` value of a type conforming to ` CustomTestExecuting ` . A ` nil ` value
198
- from this property will skip calling the ` execute(...) ` method.
199
- - A default implementation of ` Trait.customTestExecutor ` whose value is ` nil ` .
200
- - A conditional implementation of ` Trait.customTestExecutor ` whose value is
201
- ` self ` in the common case where the trait type conforms to
202
- ` CustomTestExecuting ` itself.
203
-
204
- Since the ` customTestExecutor ` property is optional and ` nil ` by default, the
205
- testing library cannot invoke the ` execute(...) ` method unless a trait
206
- customizes test behavior. This avoids the "unnecessarily lengthy backtraces"
207
- problem above.
199
+ - A new protocol ` TestExecuting ` with a single required ` execute(...) ` method.
200
+ This will be called to run a test, and allows the conforming type to perform
201
+ custom logic before or after.
202
+ - A new property ` testExecutor ` on the ` Trait ` protocol whose type is an
203
+ ` Optional ` value of a type conforming to ` TestExecuting ` . A ` nil ` value for
204
+ this property will skip calling the ` execute(...) ` method.
205
+ - A default implementation of ` Trait.testExecutor ` whose value is ` nil ` .
206
+ - A conditional implementation of ` Trait.testExecutor ` whose value is ` self `
207
+ in the common case where the trait type conforms to ` TestExecuting ` itself.
208
+
209
+ Since the ` testExecutor ` property is optional and ` nil ` by default, the testing
210
+ library cannot invoke the ` execute(...) ` method unless a trait customizes test
211
+ behavior. This avoids the "unnecessarily lengthy backtraces" problem above.
208
212
209
213
Below are the proposed interfaces:
210
214
@@ -215,12 +219,12 @@ Below are the proposed interfaces:
215
219
///
216
220
/// Types conforming to this protocol may be used in conjunction with a
217
221
/// ``Trait``-conforming type by implementing the
218
- /// ``Trait/customTestExecutor-1dwpt `` property, allowing custom traits to
222
+ /// ``Trait/testExecutor-714gp `` property, allowing custom traits to
219
223
/// customize the execution of tests. Consolidating common set-up and tear-down
220
224
/// logic for tests which have similar needs allows each test function to be
221
225
/// more succinct with less repetitive boilerplate so it can focus on what makes
222
226
/// it unique.
223
- public protocol CustomTestExecuting : Sendable {
227
+ public protocol TestExecuting : Sendable {
224
228
/// Execute a function for the specified test and/or test case.
225
229
///
226
230
/// - Parameters:
@@ -241,8 +245,8 @@ public protocol CustomTestExecuting: Sendable {
241
245
/// When the testing library is preparing to run a test, it finds all traits
242
246
/// applied to that test (including those inherited from containing suites)
243
247
/// and asks each for the value of its
244
- /// ``Trait/customTestExecutor-1dwpt `` property. It then calls this method on
245
- /// all non-`nil` instances, giving each an opportunity to perform
248
+ /// ``Trait/testExecutor-714gp `` property. It then calls this method
249
+ /// on all non-`nil` instances, giving each an opportunity to perform
246
250
/// arbitrary work before or after invoking `function`.
247
251
///
248
252
/// This method should either invoke `function` once before returning or throw
@@ -259,42 +263,42 @@ public protocol CustomTestExecuting: Sendable {
259
263
public protocol Trait : Sendable {
260
264
// ...
261
265
262
- /// The type of the custom test executor for this trait.
266
+ /// The type of the test executor for this trait.
263
267
///
264
268
/// The default type is `Never`, which cannot be instantiated. This means the
265
- /// value of the ``customTestExecutor-1dwpt `` property for all traits with the
266
- /// default custom executor type is `nil`, meaning such traits will not
269
+ /// value of the ``testExecutor-714gp `` property for all traits with
270
+ /// the default custom executor type is `nil`, meaning such traits will not
267
271
/// perform any custom execution for the tests they're applied to.
268
- associatedtype CustomTestExecutor : CustomTestExecuting = Never
272
+ associatedtype TestExecutor : TestExecuting = Never
269
273
270
- /// The custom test executor for this trait, if any.
274
+ /// The test executor for this trait, if any.
271
275
///
272
- /// If this trait's type conforms to ``CustomTestExecuting ``, the default
273
- /// value of this property is `self` and this trait will be used to customize
274
- /// test execution. This is the most straightforward way to implement a trait
275
- /// which customizes the execution of tests.
276
+ /// If this trait's type conforms to ``TestExecuting ``, the default value of
277
+ /// this property is `self` and this trait will be used to customize test
278
+ /// execution. This is the most straightforward way to implement a trait which
279
+ /// customizes the execution of tests.
276
280
///
277
281
/// If the value of this property is an instance of a different type
278
- /// conforming to ``CustomTestExecuting ``, that instance will be used to
279
- /// perform custom test execution instead.
282
+ /// conforming to ``TestExecuting ``, that instance will be used to perform
283
+ /// test execution instead.
280
284
///
281
285
/// The default value of this property is `nil` (with the default type
282
286
/// `Never?`), meaning that instances of this type will not perform any custom
283
287
/// test execution for tests they are applied to.
284
- var customTestExecutor: CustomTestExecutor ? { get }
288
+ var testExecutor: TestExecutor ? { get }
285
289
}
286
290
287
- extension Trait where Self : CustomTestExecuting {
291
+ extension Trait where Self : TestExecuting {
288
292
// Returns `self`.
289
- public var customTestExecutor : Self ? { get }
293
+ public var testExecutor : Self ? {
290
294
}
291
295
292
- extension Trait where CustomTestExecutor == Never {
296
+ extension Trait where TestExecutor == Never {
293
297
// Returns `nil`.
294
- public var customTestExecutor: CustomTestExecutor ? { get }
298
+ public var testExecutor: TestExecutor ? {
295
299
}
296
300
297
- extension Never : CustomTestExecuting {}
301
+ extension Never : TestExecuting {}
298
302
```
299
303
300
304
Here is a complete example of the usage scenario described earlier, showcasing
@@ -306,7 +310,7 @@ func example() {
306
310
// ...validate API usage, referencing `APICredentials.current`...
307
311
}
308
312
309
- struct MockAPICredentialsTrait : TestTrait , CustomTestExecuting {
313
+ struct MockAPICredentialsTrait : TestTrait , TestExecuting {
310
314
func execute (_ function : @Sendable () async throws -> Void , for test : Test, testCase : Test.Case? ) async throws {
311
315
let mockCredentials = APICredentials (apiKey : " ..." )
312
316
try await APICredentials.$current.withValue (mockCredentials) {
@@ -357,26 +361,26 @@ concurrency technique and reduces the potential for test parallelization.
357
361
### Add `execute (... )` directly to the `Trait` protocol
358
362
359
363
The proposed `execute (... )` method could be added as a requirement of the
360
- ` Trait ` protocol instead of being part of a separate ` CustomTestExecuting `
361
- protocol, and it could have a default implementation which directly invokes the
362
- passed-in closure. But this approach would suffer from the lengthy backtrace
363
- problem described above.
364
+ `Trait` protocol instead of being part of a separate `TestExecuting` protocol,
365
+ and it could have a default implementation which directly invokes the passed - in
366
+ closure. But this approach would suffer from the lengthy backtrace problem
367
+ described above.
364
368
365
369
### Extend the `Trait` protocol
366
370
367
371
The original, experimental implementation of this feature included a protocol
368
372
named`CustomExecutionTrait` which extended `Trait` and had roughly the same
369
- method requirement as the ` CustomTestExecuting ` protocol proposed above. This
370
- design worked, provided scoped access, and avoided the lengthy backtrace problem.
373
+ method requirement as the `TestExecuting ` protocol proposed above. This design
374
+ worked, provided scoped access, and avoided the lengthy backtrace problem.
371
375
372
376
After evaluating the design and usage of this SPI though, it seemed unfortunate
373
377
to structure it as a sub- protocol of `Trait` because it means that the full
374
378
capabilities of the trait system are spread across multiple protocols. In the
375
- proposed design, the ability to provide a custom test executor value is exposed
376
- via the main ` Trait ` protocol, and it relies on an associated type to
377
- conditionally opt-in to custom test behavior. In other words, the proposed
378
- design expresses custom test behavior as just a _ capability_ that a trait may
379
- have, rather than a distinct sub-type of trait.
379
+ proposed design, the ability to provide a test executor value is exposed via the
380
+ main `Trait` protocol, and it relies on an associated type to conditionally
381
+ opt- in to custom test behavior. In other words, the proposed design expresses
382
+ custom test behavior as just a _capability_ that a trait may have, rather than a
383
+ distinct sub- type of trait.
380
384
381
385
Also, the implementation of this approach within the testing library was not
382
386
ideal as it required a conditional `trait as? CustomExecutionTrait` downcast at
0 commit comments