【问题标题】:API violation - multiple calls made to -[XCTestExpectation fulfill], How can i solve this problemAPI 违规 - 多次调用 -[XCTestExpectation 实现],我该如何解决这个问题
【发布时间】: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


【解决方案1】:

你的代码有点奇怪。但看起来您正在向someOtherStream 发送两个值。所以预计sink会被调用两次。

【讨论】:

    猜你喜欢
    • 2014-09-29
    • 2015-03-27
    • 2020-03-25
    • 2020-02-14
    • 2021-10-23
    • 1970-01-01
    相关资源
    最近更新 更多