我如何模拟资源响应?

时间:2016-10-03 08:13:48

标签: siesta-swift

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

但是,返回Resource的方法并不那么简单,因为Resource是最终类而不是协议。
我想创建一个模拟{{1调用Resource等时没有做任何真实的网络请求,并暴露某种方式伪造成功/失败,触发添加到load()的观察者。

目前有没有办法做到这一点?

2 个答案:

答案 0 :(得分:5)

您有几种选择:

存根NetworkingProvider

使用自定义NetworkingProvider实施创建您的服务。

// App

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

// Tests

myAppNetworkingProvider = NetworkStub()

如果您希望一次存根多个回复,则StubbedNetworkingProvider可以返回单个硬编码的URLResponse,或匹配URLRequest

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

存根网络

Siesta使用网络存根库,例如OHHTTPStubsMockingjayNocilla。 (Siesta本身使用Nocilla进行内部回归测试,虽然该库具有内部竞争条件,但在撰写本文时并未得到特别好的维护,所以我不能全心全意地推荐它。)

对网络本身进行存储可以测试应用与底层网络API的完全交互。这种方法可能最适合全面集成测试,特别是如果您想要记录和重放来自真实API的响应。

自定义资源协议

由于Swift支持retroactive modelingResource不需要(或实现)可测试协议。您可以创建自己的一个:

protocol ResourceProtocol {
  // Resource methods your app uses
}

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

这听起来最像您在原始问题中寻找的内容。但是,我不特别推荐它:

  • 这是最复杂的实施 - 而且最容易出错。您会发现准确模仿Siesta的所有行为都会非常困难。相信我:资源API起初看起来很无辜,但如果你尝试以这种方式运用你的整个应用程序,你会发现自己重新实现了一半的库。
  • 它可能会错过问题,而不会发现回归。使用Siesta的许多危险点都与确切的调用顺序有关:哪些事件发生以及以什么顺序发生,在主运行循环的后续转弯中发生什么,观察者/所有者关系做什么或不做什么创建保留周期等等。您必须对所有这些事情做出假设,并且最终会根据您的假设测试您的代码 - 而不是针对图书馆的真实行为。

简而言之,与其他方法相比,较低价值的努力更高。这肯定不是进行回归测试的有效方法。

那就是说,如果你坚持纯粹主义者“不要超越界限”的单元测试理念,那么就是这样做的方法。

答案 1 :(得分:1)

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

以下是我如何设置URLMock以使用Siesta:

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)
}