【问题标题】:How to create unit test cases with closures如何使用闭包创建单元测试用例
【发布时间】:2020-07-29 12:31:52
【问题描述】:

我已经在我的应用程序中创建了单元测试用例,到目前为止还不错。我在我的项目中使用 MVVM 并且我的 API 请求具有 success & failureclosures。我怎样才能为此制作测试用例。

我尝试了什么:

var mockAPIService: MockApiService!

override func setUp() {
  super.setUp()
  mockAPIService = MockApiService()
  sut = PhotoListViewModel(apiService: mockAPIService)
}

func test_fetch_photo() {
  sut.apiSuccessClouser = { dataValue in
    print("apiSuccessClouser") // This doesnot executes 
    XCTAssert(dataValue)
  }
}

但是print("apiSuccessClouser") 没有执行.. 我只是在寻找 make clouser 与单元测试一起工作。

【问题讨论】:

  • 请分享您要测试的代码大纲,而不仅仅是您的测试代码。目前尚不清楚您要测试什么,任何可能的答案都取决于此。

标签: ios swift unit-testing xctest


【解决方案1】:

将 dataValue 存储在某个变量中,并使用期望等待您的闭包执行然后进行测试。注意:这个例子是用swift 4编写的

let yourExpectationName = expectation(description: "xyz")
var dataToAssert = [String]() //replace with you data type
sut.apiSuccessClouser = { dataValue in
      dataToAssert = dataValue
      yourExpectationName.fulfill()
 }
    
waitForExpectations(timeout: 3) { (error) in //specify wait time in seconds
    XCTAssert(dataToAssert)
}

【讨论】:

  • 谢谢.. expectation 替换为 XCTestExpectation 并且有效。顺便问一下,您能否更新答案我们如何使用 Quick/Nimble 来做到这一点?
【解决方案2】:

MockApiService 中的apiSuccessClouser 是闭包(()->Void?)? 类型的属性。

sut.apiSuccessClouser = { ... } 行中,您为属性 apiSuccessClouser 分配了一个闭包,但您从未访问此闭包以便执行 print("apiSuccessClouser")

要执行 print("apiSuccessClouser") 你需要调用闭包

sut.apiSuccessClouser?()

所以像这样重构测试:

func test_fetch_photo() {
  sut.apiSuccessClouser = { dataValue in
  print("apiSuccessClouser") // This doesnot executes 
  XCTAssert(dataValue)
 }
sut.apiSuccessClouser?()
}

更多信息:https://docs.swift.org/swift-book/LanguageGuide/Closures.html

【讨论】:

    【解决方案3】:

    要使用 vanilla XCTest 测试这种异步代码,您需要使用 XCTestExpectation

    func test_fetch_photo() {
      let expectation = XCTestExpectation(description: "photo is fetched")
    
      sut.apiSuccessClouser = { dataValue in
        // I like to run the assertions directly inside of the async closure, that way
        // you don't need to have vars around to store the value in order to check it
        // afterwards
        XCTAssert(dataValue)
    
        expectation.fulfill()
      }
    
      sut.apiSuccessClouser?()
    
      // The timeout duration depends on what kind of async work the closure is doing,
      // here, because it's called directly, you probably don't need long.
      wait(for: [expectation], timeout: 0.1)
    }
    

    断言库Nimble 还提供了一种测试异步代码的简洁方法。

    func test_fetch_photo() {
      waitUntil { done in
        self.sut.apiSuccessClouser = { dataValue in
          assert(dataValue).toNot(beNil())
          done()
        }
    
        self.sut.apiSuccessClouser?()
      }
    }
    

    除了waitUntil,Nimble 还有一个.toEventually assertion

    您也询问过使用Quick。 Quick 是一个测试 harness 库,它允许您以不同的方式编写测试,但它不会影响您编写实际期望的方式。

    describe("Name of your system under test") {
      it("does something asynchronously") {
        let sut = ...
        
        waitUntil { done in
          self.sut.apiSuccessClouser = { dataValue in
            assert(dataValue).toNot(beNil())
            done()
          }
    
          self.sut.apiSuccessClouser?()
        }
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2016-06-21
      • 1970-01-01
      • 1970-01-01
      • 2016-02-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-08
      • 2018-06-19
      相关资源
      最近更新 更多