如果未调用闭包,如何使XCTest失败?

时间:2018-03-18 16:15:44

标签: swift unit-testing asynchronous closures xctest

我有以下单元测试:

let apiService = FreeApiService(httpClient: httpClient)
apiService.connect() {(status, error) in
     XCTAssertTrue(status)
     XCTAssertNil(error)
}

实际功能如下:

typealias freeConnectCompleteClosure = ( _ status: Bool, _ error: ApiServiceError?)->Void

class FreeApiService : FreeApiServiceProtocol {
    func connect(complete: @escaping freeConnectCompleteClosure) {
       ...
       case 200:
            print("200 OK")
            complete(true, nil)
    }
}

这个单元测试正在通过,但问题是,如果我忘记了complete(true, nil)部分,测试仍然会通过。如果没有调用闭包,我找不到默认情况下使测试失败的方法。

我错过了什么?

2 个答案:

答案 0 :(得分:2)

您需要使用XCTTestExpectation。除非明确履行,否则将无法通过测试。

通过调用expectation(description:)或其中一个相关方法,将期望作为测试方法设置的一部分。在测试中的回调内部,根据期望调用fulfill()。最后,在致电connect()后,拨打XCTestCase的“等待”方法之一,例如waitForExpectations(timeout:)。如果您忘记在应用程序代码中调用回调,则超时将会过去,您将不会再出现误报。

Apple的"Testing Asynchronous Operations with Expectations"文档中提供了一个完整的示例。

答案 1 :(得分:1)

看起来您正在尝试针对FreeApiService编写测试。但是,从名称(和完成处理程序)判断,FreeApiService进行网络调用。这是单元测试中要避免的,因为测试不再仅仅依赖于您的代码。这取决于

  • 拥有可靠的互联网连接
  • 后端正在上升
  • 后端在给定的超时前响应
  • 发出预期回复的后端

如果您愿意忍受片状(由于上述依赖性)和缓慢(由于网络延迟)导致的测试,那么您可以编写异步测试。它看起来像这样:

func testConnect_ShouldCallCompletionHandlerWithTrueStatusAndNilError() {
    let apiService = FreeApiService(httpClient: httpClient)
    var capturedStatus: Bool?
    var capturedError: Error?

    let promise = expectation(description: "Completion handler invoked")
    apiService.connect() {(status, error) in
        capturedStatus = status
        capturedError = error
        promise.fulfill()
    }
    waitForExpectations(timeout: 5, handler: nil)

    XCTAssertTrue(capturedStatus ?? false, "status")
    XCTAssertNil(capturedError, "error")
}

如果未调用完成处理程序,waitForExpectations将在5秒后超时。结果将导致测试失败。

我避免在完成处理程序中放置断言。相反,正如我在A Design Pattern for Tests that Do Real Networking中所描述的那样,我建议:

  • 捕获我们想要测试的参数
  • 触发转义标志

然后可以在完成处理程序之外执行所有断言。

...但是!我尝试为后端系统本身的验收测试保留异步测试。如果你想测试自己的代码,异步测试的混乱性质表明被测代码的设计需要改进。网络呼叫形成了明确的界限。我们可以测试到那个边界。而且我们可以测试任何被抛回我们身上的东西,但是我们可以在边界上进行测试。换句话说,我们可以测试:

  • 网络请求是否正确形成?但是不要发出请求。
  • 我们是否正确处理网络响应?但要模拟回复。

重塑代码以允许这些测试可以让我们编写快速且确定的测试。他们甚至不需要互联网连接。