swiftlang / swift

The Swift Programming Language
https://swift.org
Apache License 2.0
67.56k stars 10.35k forks source link

Unable to use RunLoop to allow task to advance #76882

Open jonreid opened 3 weeks ago

jonreid commented 3 weeks ago

Description

Say we have a UIKit table view controller which loads its data by doing this inside viewDidLoad():

Task {
    results = await viewModel.load()
    self.tableView.reloadData()
}

I am able to test this in XCTest by pumping the run loop. This does not work in Swift Testing.

Expected behavior

With XCTest, I can allow the task to proceed by polling for the expected results in a loop that calls:

RunLoop.current.run(until: Date(timeIntervalSinceNow: 0.01))

Actual behavior

With Swift Testing, pumping the run loop does not advance the task.

I added print statements in 2 places: one inside the Task after the await, and another at the end of the test case, both XCTest and Swift Testing.

Steps to reproduce

In https://github.com/jonreid/ExpectToEventuallyEqual there is a SampleApp that contains both XCTest and Swift Testing targets. The print statements are in place inside TableViewController viewDidLoad(), and at the end of test_numberOfRows and numberOfRows. Run each to see the difference in behavior.

swift-testing version/commit hash

Xcode 16.0.0 built-in

Swift & OS version (output of swift --version ; uname -a)

swift-driver version: 1.115 Apple Swift version 6.0 (swiftlang-6.0.0.9.10 clang-1600.0.26.2) Target: arm64-apple-macosx14.0 Darwin Llama.local 23.6.0 Darwin Kernel Version 23.6.0: Mon Jul 29 21:14:30 PDT 2024; root:xnu-10063.141.2~1/RELEASE_ARM64_T6000 arm64

grynspan commented 3 weeks ago

Just to clarify: is the test in question marked @MainActor? Is it async?

jonreid commented 3 weeks ago

It is @MainActor. Tried both with and without async.

grynspan commented 3 weeks ago

Alright, thanks. Interactions between the main actor and main run loop are controlled by the Swift runtime, so I'm going to move this issue to the main Swift repo.