I'm writing unit test for my codes which using Combine framework
i have a async operation, so i use expectation(descrption:) to wait async operation
this is my code example
class MyViewModel {
private var someOtherSubject: CurrentValueSubject<...>(...)
var someOtherStream: ... {
return someOtherSubject.eraseToAnyPublisher()
}
init(...) {
.
.
bind()
}
private func bind() {
.
.
.
someOfMySubject
.flatMap { someAsyncOperation }
.sink { [weak self] ... in
self?.someOtherSubject.send(value2)
}
.store(..)
}
.
.
func handleSomeUserAction() {
self.someOtherSubject.send(value1)
self.someOfMySubject.send(someEvent)
}
}
i'm trying to check value which emitted by someOtherStream when handleSomeUserAction is called
so i wrote test code like this
func test_handleSomeUserAction() {
// given
let expectation = expectation(description: "...")
var result: ValueType?
// when
sut.someOtherStream
.dropFirst() // drop CurretValueSubject's default value
.sink {
result = $0
expectation.fulfill()
}
.store(...)
sut.handleSomeUserAction()
// then
wait(for: [expectation], timeout: 1.0)
let unwrapped = try XCTUnwrap(result)
XCTAssertEqual(unwrapped, value1)
}
i know expectedFulfillmentCount is 1 because it's default value is 1
but test is failed and Xcode show me this message
API violation - multiple calls made to -[XCTestExpectation fulfill]
so i tried to debug, and i figured out expectation.fulfill() called twice despite of expectedFulfillmentCount is 1
and result is value2 not value1 that i expected
why this happend? i think async operation(flatMap {...}) is finished too fast and fulfill called twice.
i tried delay mock method but i think this is not the right solution
You code is kind of strange. But it looks like you are sending two values to
someOtherStream. So it is expected that the sink is called twice.