我正在尝试为我的网络电话编写失败的测试,但无论如何都无法从我的测试中访问连接设置。
此代码适用于测试成功案例:
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)
}
那里有任何解决方案可以处理我所追求的事情,或者我是否会解决这个问题?
答案 0 :(得分:1)
请查看有关Apple的网络链接调节器的NSHipster article。有很多预设,您可以创建自己的自定义网络配置文件。不幸的是,似乎没有办法在代码中限制网络。
然而,一个可行的替代方法是使用ReactiveCocoa并将所有网络事件建模为SignalProducers
。然后,您可以使用throttle
或wait
功能,具体取决于您的意图。
答案 1 :(得分:1)
我最后只是嘲笑网络电话,说实话比在实际连接上执行测试要好得多,因为无论如何这些都是非常不可靠的。
这是我的模拟NSURLSession
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)
}
}
}
以下是我在测试中使用它的方法:
请注意,即使没有网络延迟,您仍然必须使用expectation
。
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