如果未调用闭包,我如何使 XCTest 失败?
How can I fail an XCTest if a closure isn't invoked?
我有以下单元测试:
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)
部分,测试仍然会通过。如果没有调用闭包,我找不到让我的测试默认失败的方法。
我错过了什么?
为此您需要使用 XCTTestExpectation
。除非明确满足,否则将无法通过测试。
通过调用 expectation(description:)
or one of the related methods. Inside the callback in your test, invoke fulfill()
on the expectation. Finally, after your call to connect()
, call one of XCTestCase
's "wait" methods, such as waitForExpectations(timeout:)
创建期望作为测试方法设置的一部分。如果您忘记在您的应用程序代码中调用回调,超时将会过去,您将不再有误报。
Apple 的 "Testing Asynchronous Operations with Expectations" 文档中提供了完整示例。
您似乎正在尝试针对 FreeApiService 编写测试。但是,从名称(和完成处理程序)来看,FreeApiService 进行了网络调用。这是在单元测试中要避免的事情,因为测试不再仅仅依赖于你的代码。这取决于
- 拥有可靠的互联网连接
- 后端启动中
- 后端在给定之前响应time-out
- 后端发出预期响应
如果您愿意忍受不稳定(由于上述依赖性)和缓慢(由于网络延迟)的测试,那么您可以编写异步测试。它看起来像这样:
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 中描述的那样,我建议:
- 捕获我们要测试的参数
- 触发转义标志
然后可以在完成处理程序之外执行所有断言。
……但是!我尝试为 back-end 系统本身的验收测试保留异步测试。如果您想测试自己的代码,异步测试的混乱性质表明被测代码的设计需要改进。网络调用形成了清晰的边界。我们可以测试到那个边界。我们可以测试任何被扔回给我们的东西,但在我们这边的边界上。也就是说,我们可以测试:
- 网络请求格式是否正确?但不要发出请求。
- 我们是否正确处理网络响应?但是模拟响应。
重塑代码以允许这些测试将使我们能够编写快速且确定的测试。他们甚至不需要互联网连接。
我有以下单元测试:
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)
部分,测试仍然会通过。如果没有调用闭包,我找不到让我的测试默认失败的方法。
我错过了什么?
为此您需要使用 XCTTestExpectation
。除非明确满足,否则将无法通过测试。
通过调用 expectation(description:)
or one of the related methods. Inside the callback in your test, invoke fulfill()
on the expectation. Finally, after your call to connect()
, call one of XCTestCase
's "wait" methods, such as waitForExpectations(timeout:)
创建期望作为测试方法设置的一部分。如果您忘记在您的应用程序代码中调用回调,超时将会过去,您将不再有误报。
Apple 的 "Testing Asynchronous Operations with Expectations" 文档中提供了完整示例。
您似乎正在尝试针对 FreeApiService 编写测试。但是,从名称(和完成处理程序)来看,FreeApiService 进行了网络调用。这是在单元测试中要避免的事情,因为测试不再仅仅依赖于你的代码。这取决于
- 拥有可靠的互联网连接
- 后端启动中
- 后端在给定之前响应time-out
- 后端发出预期响应
如果您愿意忍受不稳定(由于上述依赖性)和缓慢(由于网络延迟)的测试,那么您可以编写异步测试。它看起来像这样:
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 中描述的那样,我建议:
- 捕获我们要测试的参数
- 触发转义标志
然后可以在完成处理程序之外执行所有断言。
……但是!我尝试为 back-end 系统本身的验收测试保留异步测试。如果您想测试自己的代码,异步测试的混乱性质表明被测代码的设计需要改进。网络调用形成了清晰的边界。我们可以测试到那个边界。我们可以测试任何被扔回给我们的东西,但在我们这边的边界上。也就是说,我们可以测试:
- 网络请求格式是否正确?但不要发出请求。
- 我们是否正确处理网络响应?但是模拟响应。
重塑代码以允许这些测试将使我们能够编写快速且确定的测试。他们甚至不需要互联网连接。