使用URLProtocol子类化做单元测试:Data返回0字节而非nil
iOS单元测试中MockURLProtocol返回nil data却变成0字节Data的问题
首先,抱歉我的英文表述可能不够流畅。我正在为学校项目开发一款iOS应用,遇到了一个问题。我通过URLProtocol方法对API调用进行单元测试。
API调用代码
task?.cancel() task = exchangeSession.dataTask(with: request) { data, response, error in // The dataTask method will execute in a separate queue, so we // get back into the main one because // we will modify the user interface with our exchange result DispatchQueue.main.async { guard let data = data, error == nil else { callback(false, nil, error) return } guard let response = response as? HTTPURLResponse, response.statusCode == 200 else { callback(false, nil, nil) return } guard let responseJSON = try? JSONDecoder().decode(ConvertResponse.self, from: data), let result = responseJSON.result else { callback(false, nil, nil) return } callback(true, result, nil) } } task?.resume()
MockURLProtocol实现
final class MockURLProtocol: URLProtocol { // We return true in order to allow URLSession to use this protocol for any URL Request override class func canInit(with request: URLRequest) -> Bool { return true } override class func canonicalRequest(for request: URLRequest) -> URLRequest { return request } static var loadingHandler: ((URLRequest) -> (Data?, HTTPURLResponse?, Error?))? override func startLoading() { guard let handler = MockURLProtocol.loadingHandler else { print("Loading handler is not set.") return } let (data, response, error) = handler(request) guard error == nil else { client?.urlProtocol(self, didFailWithError: error!) return } if let data = data { client?.urlProtocol(self, didLoad: data) } if let response = response { client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed) } client?.urlProtocolDidFinishLoading(self) } override func stopLoading() {} }
如你所见,它包含一个可返回data、response和error的handler。
在其中一个测试用例中,我想验证无数据的场景,因此将data参数设为nil。
测试代码
func testConvertShouldPostFailedCallbackIfNoData() { MockURLProtocol.loadingHandler = { request in return (nil, nil, nil) } let expectation = XCTestExpectation(description: "Wait for queue change.") client.convert(from: from, to: to, amount: amount) { success, result, error in XCTAssertFalse(success) XCTAssertNil(result) XCTAssertNil(error) expectation.fulfill() } wait(for: [expectation], timeout: 0.01) }
我的问题是:data参数并未返回nil,而是显示为“0 Bytes”,但error和response设为nil却能正常生效。
测试结果:测试中传入的nil data被转为0字节的Data,导致代码无法进入预期的逻辑分支。
我想请教为什么data参数不是nil?0字节的Data不会被判定为nil,导致我的代码无法进入正确的逻辑分支。
我尝试了很多断点调试仍未找到原因,但发现一个奇怪的现象:如果在handler中设置error并将data设为nil,此时data会是nil。这可能和didFailWithError函数有关吗?该函数是否会强制将data设为nil?
内容的提问来源于stack exchange,提问作者Jintae
相关产品推荐
相关产品推荐

