File: testing-asynchronous-code.md

package info (click to toggle)
swiftlang 6.1.3-4
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 2,791,644 kB
  • sloc: cpp: 9,901,738; ansic: 2,201,433; asm: 1,091,827; python: 308,252; objc: 82,166; f90: 80,126; lisp: 38,358; pascal: 25,559; sh: 20,429; ml: 5,058; perl: 4,745; makefile: 4,484; awk: 3,535; javascript: 3,018; xml: 918; fortran: 664; cs: 573; ruby: 396
file content (99 lines) | stat: -rw-r--r-- 3,468 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# Testing asynchronous code

<!--
This source file is part of the Swift.org open source project

Copyright (c) 2024 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception

See https://swift.org/LICENSE.txt for license information
See https://swift.org/CONTRIBUTORS.txt for Swift project authors
-->

Validate whether your code causes expected events to happen.

## Overview

The testing library integrates with Swift concurrency, meaning that in many
situations you can test asynchronous code using standard Swift
features.  Mark your test function as `async` and, in the function
body, `await` any asynchronous interactions:

```swift
@Test func priceLookupYieldsExpectedValue() async {
  let mozarellaPrice = await unitPrice(for: .mozarella)
  #expect(mozarellaPrice == 3)
}
```

In more complex situations you can use ``Confirmation`` to discover whether an
expected event happens.

### Confirm that an event happens

Call ``confirmation(_:expectedCount:isolation:sourceLocation:_:)-5mqz2`` in your
asynchronous test function to create a `Confirmation` for the expected event. In
the trailing closure parameter, call the code under test. Swift Testing passes a
`Confirmation` as the parameter to the closure, which you call as a function in
the event handler for the code under test when the event you're testing for
occurs:

```swift
@Test("OrderCalculator successfully calculates subtotal for no pizzas")
func subtotalForNoPizzas() async {
  let calculator = OrderCalculator()
  await confirmation() { confirmation in
    calculator.successHandler = { _ in confirmation() }
    _ = await calculator.subtotal(for: PizzaToppings(bases: []))
  }
}
```

If you expect the event to happen more than once, set the
`expectedCount` parameter to the number of expected occurrences. The
test passes if the number of occurrences during the test matches the
expected count, and fails otherwise.

You can also pass a range to ``confirmation(_:expectedCount:isolation:sourceLocation:_:)-l3il``
if the exact number of times the event occurs may change over time or is random:

```swift
@Test("Customers bought sandwiches")
func boughtSandwiches() async {
  await confirmation(expectedCount: 0 ..< 1000) { boughtSandwich in
    var foodTruck = FoodTruck()
    foodTruck.orderHandler = { order in
      if order.contains(.sandwich) {
        boughtSandwich()
      }
    }
    await FoodTruck.operate()
  }
}
```

In this example, there may be zero customers or up to (but not including) 1,000
customers who order sandwiches. Any [range expression](https://developer.apple.com/documentation/swift/rangeexpression)
which includes an explicit lower bound can be used:

| Range Expression | Usage |
|-|-|
| `1...` | If an event must occur _at least_ once |
| `5...` | If an event must occur _at least_ five times |
| `1 ... 5` | If an event must occur at least once, but not more than five times |
| `0 ..< 100` | If an event may or may not occur, but _must not_ occur more than 99 times |

### Confirm that an event doesn't happen

To validate that a particular event doesn't occur during a test,
create a `Confirmation` with an expected count of `0`:

```swift
@Test func orderCalculatorEncountersNoErrors() async {
  let calculator = OrderCalculator()
  await confirmation(expectedCount: 0) { confirmation in
    calculator.errorHandler = { _ in confirmation() }
    calculator.subtotal(for: PizzaToppings(bases: []))
  }
}
```