Test The Publisher Of A @Published Property
John Sundell wrote a blog post about how to test Combine-based code. In the article he shows how to write unit tests for a publisher that tokenises a string. Great article as always and you should read it.
This blog post here is just a reminder for me how to change Johns XCTestCase
extension to test the publisher of a @Published
property.
Without further ado here is the extension:
extension XCTestCase {
func _awaitPublishedChange<T: Publisher>(
_ publisher: T,
changeAction: () -> Void = {},
timeout: TimeInterval = 1,
file: StaticString = #file,
line: UInt = #line
) throws -> T.Output where T.Failure == Never {
var result: Result<T.Output, Error>?
let expectation = self.expectation(description: "Awaiting publisher")
let cancellable = publisher
.dropFirst()
.sink(receiveValue: { value in
result = .success(value)
expectation.fulfill()
})
changeAction()
waitForExpectations(timeout: timeout)
cancellable.cancel()
let unwrappedResult = try XCTUnwrap(
result,
"Awaited publisher did not produce any output",
file: file,
line: line
)
return try unwrappedResult.get()
}
}
And this is how to use it:
func test_addEvent_shouldPublishChangedEvents() throws {
let fileManagerMock = FileManagerProtocolMock()
fileManagerMock.eventsURLReturnValue =
documentsURL(for: dummyEventsFilename)
let sut = EventStore(fileManager: fileManagerMock)
sut.events = [Event(name: "Bla",
date: Date(timeIntervalSinceNow: -1000))]
let events = try _awaitPublishedChange(
sut.$events,
changeAction: {
sut.add(Event(name: "Foo", date: Date()))
})
XCTAssertEqual(events.count, 2)
}