单元测试在Swift中使用NSURLSession的类

时间:2015-06-26 14:37:09

标签: swift unit-testing nsurlsession

我正在寻找一种最有效的方法来对使用NSURLSession从URL检索数据的类进行单元测试。我已经看到了实现NSURLConnectionDelegate协议的类的较旧示例。从阅读NSURLSession类参考文档,到使用相同的方法,我的类必须实现NSURLSessionDataDelegate协议。我相信这也需要实现NSURLSessionTaskDelegateNSURLSessionDelegate协议,这些协议一起包含许多我不需要的方法。

是否有更简单的方法来实现相同的目标?

感谢。

1 个答案:

答案 0 :(得分:0)

我更喜欢使用面向协议的编程和协议扩展来测试NSURLSession。以下是我的博文"Testing NSURLSession with Swift, Part 1: Mocking Classes You Don't Own"的摘要。

首先,为NSURLSessionDataTask创建一个协议,以便用测试中的模拟代替它。

typealias DataTaskResult = (NSData?, NSURLResponse?, NSError?) -> Void

protocol URLSessionProtocol {
    func dataTaskWithURL(url: NSURL, completionHandler: DataTaskResult)
      -> NSURLSessionDataTask
}

然后扩展框架类,以便编译器知道协议和类可以互换使用。

extension NSURLSession: URLSessionProtocol { }

现在您可以创建一个模拟会话来捕获传入的参数。

class MockURLSession: URLSessionProtocol {
    private (set) var lastURL: NSURL?

    func dataTaskWithURL(url: NSURL, completionHandler: DataTaskResult) 
      -> NSURLSessionDataTask
    {
        lastURL = url
        return NSURLSessionDataTask()
    }
}

最后,测试您的HTTPClient是否向会话发送了正确的网址。

class HTTPClientTests: XCTestCase {
    var subject: HTTPClient!
    let session = MockURLSession()

    override func setUp() {
        super.setUp()
        subject = HTTPClient(session: session)
    }

    func test_GET_RequestsTheURL() {
        let url = NSURL(string: "http://masilotti.com")!

        subject.get(url) { (_, _) -> Void in }

        XCTAssert(session.lastURL === url)
    }
}

确保HTTPClient通过依赖注入公开URLSessionProtocol属性。在这里,您可以使用默认参数在未注入任何内容时获取共享会话。

class HTTPClient {
    private let session: URLSessionProtocol

    init(session: URLSessionProtocol = NSURLSession.sharedSession()) {
        self.session = session
    }

    func get(url: NSURL, completion: HTTPResult) {
        session.dataTaskWithURL(url) { (_, _, _) -> Void in }
    }
}

这可以很容易地扩展到测试更多输入,其他方法甚至输出。再次,请查看my blog post以获取更详细的说明和示例。