Ios 单元测试网络呼叫(测试失败)-Swift
我正在尝试为网络呼叫编写失败的测试,但无法在测试中找到访问连接设置的方法 此代码适用于测试成功案例:Ios 单元测试网络呼叫(测试失败)-Swift,ios,swift,unit-testing,Ios,Swift,Unit Testing,我正在尝试为网络呼叫编写失败的测试,但无法在测试中找到访问连接设置的方法 此代码适用于测试成功案例: func testRetrieveProducts() { let expectation = expectationWithDescription("asynchronous request") Requests().retrieveProducts({ (products) -> () in // check that we have two ar
func testRetrieveProducts() {
let expectation = expectationWithDescription("asynchronous request")
Requests().retrieveProducts({ (products) -> () in
// check that we have two arrays returned.
XCTAssert(products.count == 2)
expectation.fulfill()
}) { (error) -> () in
XCTFail("Request failed")
}
waitForExpectationsWithTimeout(5.0, handler: nil)
}
但我一直在寻找一种方法来测试网络超时和返回的错误数据
我可能可以通过在retrieveProducts
函数中单独调用函数并删除一些内容来测试不正确的数据,但是做一些像关闭互联网这样简单的事情被证明是相当困难的
我知道我们可以访问网络链接调节器,但每次测试都要打开和关闭它不是一个选项
我希望能够访问以下简单的内容:
func testFailRetrieveProducts() {
let expectation = expectationWithDescription("asynchronous request")
SomeNetworkClass.disableInternet()
Requests().retrieveProducts({ (products) -> () in
}) { (error) -> () in
XCTAssert(error == SomeError.TimeoutError)
}
waitForExpectationsWithTimeout(5.0, handler: nil)
}
有什么解决方案可以解决我所追求的问题,还是我的做法完全错了?看看苹果的网络链接调节器。有很多预设,您可以创建自己的自定义网络配置文件。不幸的是,似乎没有一种方法可以在代码中限制网络
然而,一种可行的替代方法是使用所有网络事件并将其建模为
信号生产者
。然后,您可以使用节流
或等待
功能,这取决于您的意图。我最后只是模拟了网络呼叫,老实说,这比在实际连接上执行测试要好得多,因为这些可能非常不可靠
这是我的模拟nsursession
class MockSession: NSURLSession {
var completionHandler:((NSData!, NSURLResponse!, NSError!) -> Void)?
static var mockResponse: (data: NSData?, urlResponse: NSURLResponse?, error: NSError?)
override class func sharedSession() -> NSURLSession {
return MockSession()
}
override func dataTaskWithRequest(request: NSURLRequest, completionHandler: (NSData?, NSURLResponse?, NSError?) -> Void) -> NSURLSessionDataTask {
self.completionHandler = completionHandler
return MockTask(response: MockSession.mockResponse, completionHandler: completionHandler)
}
class MockTask: NSURLSessionDataTask {
typealias Response = (data: NSData?, urlResponse: NSURLResponse?, error: NSError?)
var mockResponse: Response
let completionHandler: ((NSData!, NSURLResponse!, NSError!) -> Void)?
init(response: Response, completionHandler:((NSData!, NSURLResponse!, NSError!) -> Void)?) {
self.mockResponse = response
self.completionHandler = completionHandler
}
override func resume() {
completionHandler!(mockResponse.data, mockResponse.urlResponse, mockResponse.error)
}
}
}
以下是我在测试中如何使用它:
请注意,即使没有网络延迟,您仍然必须使用期望值
func testRetrieveProductsValidResponse() {
let testBundle = NSBundle(forClass: self.dynamicType)
let filepath = testBundle.pathForResource("products", ofType: "txt")
let data = NSData(contentsOfFile: filepath!)
let urlResponse = NSHTTPURLResponse(URL: NSURL(string: "https://anyURL.com")!, statusCode: 200, HTTPVersion: nil, headerFields: nil)
MockSession.mockResponse = (data, urlResponse: urlResponse, error: nil)
let requestsClass = RequestManager()
requestsClass.Session = MockSession.self
let expectation = expectationWithDescription("ready")
requestsClass.retrieveProducts("N/R FOR TEST", branchID: "N/R FOR TEST", products: { (products) -> () in
XCTAssertTrue(products.count == 7)
expectation.fulfill()
}) { (error) -> () in
XCTAssertFalse(error == Errors.NetworkError, "Its a network error")
XCTAssertFalse(error == Errors.ParseError, "Its a parse error")
XCTFail("Error not covered by previous asserts. Shouln't get to here anyway.")
expectation.fulfill()
}
waitForExpectationsWithTimeout(3.0, handler: nil)
}
最后,我的RequestManager类上有一个可访问的属性,在进行测试时可以与MockSession交换。
var Session = NSURLSession.self
您需要了解依赖项注入,并将模拟网络类注入到您的请求类上面的测试用例var Session=NSURLSession.self中的self.dynamicType和RequestManager()是什么,我需要在哪里添加它?。现在使用swift 3时情况有所不同。将很快更新并让您知道虽然网络链接调节器是非常有用的工具,但单元测试应尽可能少地依赖外部因素。在尝试构建集成测试时,这将更有帮助。