A useful extension of XCTestCase
XCTest expectations are great but it is not easy to use them.
Here is a simple extension that makes it possible to wait for a condition until it is fulfilled or timed-out.
extension XCTestCase {
/// Wait for a condition to be fulfilled
/// Example:
/// var fulfilled = false
/// wait(fulfilled)
public func wait(
_ condition: @autoclosure @escaping () -> Bool,
timeout: TimeInterval = 10,
description: String = "wait condition expectation"
) {
let expectation = self.expectation(description: description)
func testForCondition() {
if condition() {
expectation.fulfill()
} else {
DispatchQueue.main.async { testForCondition() }
}
}
testForCondition()
wait(for: [expectation], timeout: timeout)
}
}
Let’s talk about the code.
The condition is passed as a closure.
@autoclosure
is a syntactic sugar so that instead of wait({ a==b })
we can write wait(a==b)
@escaping
tells the compiler that the closure is retained.
Another line we should pay attention to:
DispatchQueue.main.async { testForCondition() }
The only reason we need DispatchQueue.main.async
is that it makes sure that testForCondition
is executed once per run-loop.
And finally the usage:
func testWaitForCondition1() throws {
var fulfilled = false
let subject = PassthroughSubject<Int, Never>()
subject
.debounce(for: .milliseconds(100),
scheduler: DispatchQueue.global())
.sink(receiveCompletion: { _ in
print("finished")
}, receiveValue: { value in
fulfilled = true
})
.store(in: &tasks)
subject.send(1)
subject.send(2)
wait(fulfilled)
}
The code can be found here.
Subscribe to The infinite monkey theorem
Get the latest posts delivered right to your inbox