我想我有这些代码行:
func reset() { initializeAnythingElse() { // AnythingElse } initializeHomeData() { // HomeData } } func initializeHomeData(callback: @escaping (()-> Void)) { getHomeConfig() { callback() } } func initializeAnythingElse(callback: @escaping (()-> Void)) { getAnythingElse() { callback() } }
我想为该代码编写一个单元测试.对于initializeHomeData和initializeAnythingElse,我可以编写单元测试,如:
func testinitializeHomeData() { let successExpectation = expectation(description: "") sut.initializeHomeData { successExpectation.fulfill() } waitForExpectations(timeout: 1.0,handler: nil) // Validation goes here } func testinitializeAnythingElse() { let successExpectation = expectation(description: "") sut.initializeAnythingElse { successExpectation.fulfill() } waitForExpectations(timeout: 1.0,handler: nil) // Validation goes here }
我的问题是,如何测试reset()?我应该在testReset()中调用它们,如:
func testReset() { testinitializeHomeData() testinitializeAnythingElse() }
但我认为这不是适当的实施.
解决方法
你是对的.要测试重置,您需要调用reset,而不是内部方法.
话虽这么说,重置目前的编写方式使其不可测试.您能够如此轻松地测试其他独立方法的原因是因为回调参数都接受了.
我建议你重写重置以允许两个可选的回调,如下所示:
typealias Callback = () -> () func reset( homeDataCallback: @escaping Callback? = nil,anythingElseCallback: @escaping Callback? = nil) { initializeAnythingElse() { anythingElseCallback?() } initializeHomeData() { homeDataCallback?() } }
请注意,此更改允许您在异步时通知这两个内部调用是否完成.
现在,您的测试方法需要在编写时考虑某种同步原语,因为从逻辑上讲,只有当主数据和其他任何内容都完成并且调用了它们的回调时,才能完成重置.
有很多方法可以实现这一点,但我将向您展示一种信号量方法:
func testReset() { let expectation = expectation(description: "reset() completes within some duration") // some mechanism to synchronize concurrent tasks // I am using a semaphore let s = dispatchSemaphore(value: 0) let homeCallback: Callback = { s.signal() // signals the completion of home data init } let anythingElseCallback: Callback = { s.signal() // signals the completions of anything else setup } // call your reset method as part of the test reset(homeDataCallback: homeCallback,anythingElseCallback: anythingElseCallback) // we kNow we need to wait for two things to complete // init home data and anything else,so do that s.wait() s.wait() // at this step,reset's internal async methods // have completed so we can Now // fulfill the expectation expectation.fulfill() }
请注意,所有这些更改都是纯粹允许您测试重置调用所必需的.函数签名允许您在现有代码中将reset()写为current,因为它具有可选参数,默认值都设置为nil.