2016-10-03 132 views
2

在我的应用程序中,我有一个封装了Service的类,并具有返回资源和请求的方法。在我的测试中,我想嘲笑请求和资源的成功/失败,而不进行任何实际的网络调用。
由于Request是一个协议,很容易通过返回一个自定义的实现,只是调用onSuccessonFailure如何模拟资源响应?

但是要做到这一点,它不是返回一个Resource方法简单,因为Resource是最后类而不是协议。
我想创建一个模拟Resource,它在调用load()等时不会执行任何实际的网络请求,并公开某种方式来伪造触发观察者添加到Resource的成功/失败。

此刻有什么办法可以做到这一点?

回答

3

您有几种选择:

的Stub NetworkingProvider

与自定义NetworkingProvider实现创建您的服务。

// App 

var myAppNetworkingProvider: NetworkingProviderConvertible = 
    URLSessionConfiguration.ephemeral // Siesta default 
... 
Service(baseURL: "...", networking: myAppNetworkingProvider) 

// Tests 

myAppNetworkingProvider = NetworkStub() 

StubbedNetworkingProvider可以返回一个硬编码的URLRequest ,或匹配,如果你想一次存根多个响应。

这是大多数应用程序的最佳选择。你可以在Siesta’s own performance tests中看到它的一个例子。它简单,快速,并提供细致的控制,但仍然可以让您用真实的Siesta行为进行测试。

存根网络

午睡可与像OHHTTPStubsMockingjayNocilla网络磕碰库。 (Siesta本身使用Nocilla进行自己的内部回归测试,虽然库本身具有内部竞争条件,并且在撰写本文时没有特别好的维护,所以我不能全心全意地推荐它。)

对网络本身进行存根拥有测试您的应用与底层网络API的完整交互的优势。这种方法对于全集成测试可能是最好的,特别是如果你想记录和重放来自真实API的响应。

自定义资源协议

由于夫特支持retroactive modelingResource不需要是(或实施)一个可测试协议。你可以创建一个你自己的:

protocol ResourceProtocol { 
    // Resource methods your app uses 
} 

// No new methods; just adding conformance 
extension Resource: ResourceProtocol { } 

这听起来最像你在你的原始问题中寻找什么。不过,我并不特别推荐它:

  • 这是最复杂的实施 - 和最容易出错。你会发现准确地模拟Siesta的所有行为令人惊讶地很难。相信我:资源API起初似乎很清白,但如果您尝试以这种方式来运用您的整个应用程序,您会发现自己重新实现了一半的库。
  • 这很可能会漏掉问题,而不是回归。使用Siesta的许多危险地点必须处理确切的调用顺序:哪些事件发生,以什么顺序发生,立即发生什么,以及主循环的后续转向,观察者/所有者关系是做什么或不做什么创建保留周期等。您必须对所有这些事情做出假设,然后最终根据您的假设测试代码 - 而不是违背图书馆的真实行为。

总之,与其他方法相比,更低的价值努力。这当然不是进行回归测试的有效方法。这就是说,如果你坚持一个纯粹主义者“不要超越界限”单元测试哲学,那么这就是做这件事的方法。

1

我正在编写一个使用Siesta的应用程序,我一直在使用URLMock来嘲笑Siesta制作的网络请求。我对结果很满意(它只是做了我想要的而没有大惊小怪),但我相信其他库也可以工作。我建议使用网络模拟库,它们具有您可能不会马上想到的功能,例如设置为在测试发出意外的网络请求时返回错误。

下面是我设置URLMock与午睡工作:

override class func setUp() { 
    super.setUp() 
    UMKMockURLProtocol.enable() 
    UMKMockURLProtocol.setVerificationEnabled(true) 
} 

override class func tearDown() { 
    UMKMockURLProtocol.setVerificationEnabled(false) 
    UMKMockURLProtocol.disable() 
    super.tearDown() 
} 

override func setUp() { 
    super.setUp() 
    // Put setup code here. This method is called before the invocation of each test method in the class. 
    UMKMockURLProtocol.reset() 
    let testConfig = URLSessionConfiguration.ephemeral 
    testConfig.protocolClasses = [UMKMockURLProtocol.self] 
    service = Service(baseURL: expectedV2Host, useDefaultTransformers: true, networking: testConfig) 
}