【发布时间】:2021-12-06 13:15:18
【问题描述】:
我正在为使用组合框架的代码编写单元测试
我有一个异步操作,所以我使用expectation(descrption:) 等待异步操作
这是我的代码示例
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)
}
}
我正在尝试检查 someOtherStream 在调用 handleSomeUserAction 时发出的值
所以我写了这样的测试代码
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)
}
我知道expectedFulfillmentCount 是 1,因为它的默认值是 1
但测试失败,Xcode 显示此消息
API 违规 - 多次调用 -[XCTestExpectation 实现]
所以我尝试调试,我发现expectation.fulfill() 调用了两次,尽管expectedFulfillmentCount 是 1
结果是value2 而不是我预期的value1
为什么会这样?我认为异步操作(flatMap {...})完成得太快,fulfill 调用了两次。
我尝试了延迟模拟方法,但我认为这不是正确的解决方案
【问题讨论】:
-
请编辑您的问题以包含适当的minimal reproducible example。您当前的问题中有很多省略的代码。你甚至没有显示你在哪里打电话
fulfill -
@Paulw11 我在代码中添加了完成。在这种情况下,如果 aync 操作退出太快,可以实现方法调用两次
-
这与速度无关。您的订阅者链被调用了两次。因为你有一个
CurrentValueSubject。它将使用初始值触发,然后在您更新值时触发。 -
@Paulw11 所以我使用 dropFirst 运算符删除了第一个元素以获取我想要接收的值
-
使用调试器。设置断点或打印您收到的值。您问题中的代码太复杂且太简化,无法跟上正在发生的事情。创建一个minimal reproducible example。这样做可能会很好地解决问题
标签: ios xctest xctestcase xctestexpectation quick-nimble