Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 单元测试网络呼叫(测试失败)-Swift_Ios_Swift_Unit Testing - Fatal编程技术网

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时情况有所不同。将很快更新并让您知道虽然网络链接调节器是非常有用的工具,但单元测试应尽可能少地依赖外部因素。在尝试构建集成测试时,这将更有帮助。