I've been trying to migrate my existing XCTest based suites to Testing and whenever I do swift concurrency dependent tests, everything seems fine. However, if I need to test some closure based APIs, then I can't find a way.
Let's imagine we have a ViewModel class with a sync interface function isolated to the MainActor that looks like this (for the sake of the simplicity of the example):
final class MyViewModel {
let analyticsTracker: AnalyticsTracker
init(analyticsTracker: AnalyticsTracker) {
self.analyticsTracker = analyticsTracker
}
@MainActor
func start() {
Task {
// something here
await somethingAsync()
// something here
analyticsTracker.track(event: .init(name: "SomeEvent", params: [:]))
}
}
private func somethingAsync() async {}
}
And I have a behavioral mock for the analytics tracker that tracks all the invocations of it's functions.
And my XCTest looks like this:
@MainActor
func test_example() async throws {
// create sut here
let expectation = expectation(description: "Async expectation")
env.analyticsTracker.trackEventMock.whenCalled { _ in
expectation.fulfill()
}
sut.start()
await fulfillment(of: [expectation], timeout: 0.001)
// do the checks here
XCTAssert(...)
}
I can't get my head around how I can translate the same to Swift Testing.
confirmation doesn't seem to work as I expected (or maybe I had a wrong expectation)
// I can't add `MainActor` here, because confirmation will not compile then
func test_example() async throws {
// create sut here ...
await confirmation { confirmed in
env.analytics.trackEventMock.whenCalled { _ in
confirmed()
}
// this should be awaited now as we're not on the main actor
await sut.start()
}
#expect(env.analytics.trackErrorMock.calledOnce)
}
In this case the confirmation never gets fired.
Is this a known issue or am I making wrong assumptions on how to test asynchronous closure-based code?
I'm on Xcode beta 4 now and I'm using built-in Testing framework (not fetching it as a swift package from Github).