# Reliably testing code that adopts Swift Concurrency?

**URL:** <https://forums.swift.org/t/reliably-testing-code-that-adopts-swift-concurrency/57304>\
**Category:** Using Swift\
**Tags:** concurrency, testing\
**Created:** [May 13, 2022, 5:14pm UTC](https://forums.swift.org/t/reliably-testing-code-that-adopts-swift-concurrency/57304 "2022-05-13T17:14:10Z")\
**Posts on this page:** 1\
**Showing post:** 1

<div class="post-metadata">

**Author:** ![stephencelis](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/stephencelis/32/2675_2.png) [@stephencelis](https://forums.swift.org/u/stephencelis)\
**Post date:** [May 13, 2022, 5:14pm UTC](https://forums.swift.org/t/reliably-testing-code-that-adopts-swift-concurrency/57304/1 "2022-05-13T17:14:10Z")

</div>

I’m having a hard time figuring out how to test application code as it adopts `async`-`await` and begins to be scheduled concurrently. I’ll try to show a simple example.

Here’s a basic SwiftUI application that tracks how many times a user has taken a screen shot. It has a view model with an endpoint that spins off some async work, and then the view calls this endpoint when it first appears:

```swift

class ViewModel: ObservableObject {
  @Published var count = 0

  @MainActor
  func task() async {
    let screenshots = NotificationCenter.default.notifications(
      named: UIApplication.userDidTakeScreenshotNotification
    )
    for await _ in screenshots {
      self.count += 1
    }
  }
}

struct ContentView: View {
  @ObservedObject var viewModel = ViewModel()

  var body: some View {
    Text("\(viewModel.count) screenshots have been taken")
      .task { await viewModel.task() }
  }
}

```

I’d like to write a test that simulates loading this screen, taking a screen shot, and asserting that the view model’s data has incremented. I’ve come up with the following:

```swift
@MainActor
func testBasics() async throws {
  let vm = ViewModel()
  let task = Task { await vm.task() }

  XCTAssertEqual(vm.count, 0)

  // Give the task an opportunity to start executing its work.
  await Task.yield()

  // Simulate a screen shot being taken.
  NotificationCenter.default.post(
    name: UIApplication.userDidTakeScreenshotNotification, object: nil
  )

  // Give the task an opportunity to update the view model.
  await Task.yield()

  XCTAssertEqual(vm.count, 1)

  task.cancel()
  await task.value
}

```

The calls to `Task.yield` feel wrong to me, but I don’t know of an alternative.

The _real_ problem with this code, though, is that the test occasionally fails! You can use Xcode’s “run repeatedly” feature 1,000 times and will almost always get a failure or two. From what I can gather, this is because there’s no guarantee that `Task.yield` will suspend long enough for the task to do its work.

I can sprinkle in more `Task.yield`s and the test fails less often:

```swift
// REALLY give the task an opportunity to start executing its work.
await Task.yield()
await Task.yield()
await Task.yield()
await Task.yield()
await Task.yield()

```

Or we could try adding explicit `Task.sleep`s, instead.

But these obviously can’t be the recommended ways of handling the problem. Both solutions are flakey and could fail at any time, and `sleep`ing slows tests down unnecessarily.

So how are we supposed to test async code like this?

I’ve pushed the project if anyone wants to mess around with it: [GitHub - stephencelis/ScreenshotWatcher: A demonstration of testing uncertainty in Swift Concurrency](https://github.com/stephencelis/ScreenshotWatcher)

---

_[View the full topic](https://forums.swift.org/t/reliably-testing-code-that-adopts-swift-concurrency/57304)._
