Combine: Blocking wait?

Is there anyway to blocking wait for X amount of elements to have been published, similiar to how RxBlocking's method func toBlocking(timeout: TimeInterval) throws -> BlockingObservable works?

Convenient for when writing tests

I suppose you could use XCTest’s expectation API instead and keep it all async

Yes, that's the proper way to write async tests in Swift, not making async API synchronous.

This is true. Yet testing publishers with expectations requires a lot of code.

That's why I just published CombineExpectations. This package aims at streamlining tests that wait for publishers.

It defines an XCTestCase method which waits for publisher expectations. Those run regular XCTestExpectations under the hood.

For example, one of those expectations is called elements:

class PublisherTests: XCTestCase {
    func testElements() throws {
        // 1. Create a publisher
        let publisher = ...
        
        // 2. Start recording the publisher
        let recorder = publisher.record()
        
        // 3. Wait for a publisher expectation
        let elements = try wait(for: recorder.elements, timeout: 1, description: "Elements")
        
        // 4. Test the result of the expectation
        XCTAssertEqual(elements, ["Hello", "World!"])
    }
}

There are other ready-made publisher expectations. Each one waits for a specific publisher aspect: first, single, completion...

I did refactor some GRDBCombine tests with CombineExpectations, in this pull request. Success is complete: tests are shorter, and more readable (IMHO). That's why I think the package is ready for a public release.

Happy CombineExpectations!

4 Likes