5

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

但是,返回 a 的方法并不是那么简单Resource,因为Resource它是最终类而不是协议。
我想创建一个在调用 etcResource时不执行任何真实网络请求的模拟load(),并公开某种方式来伪造成功/失败,从而触发添加到Resource.

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

4

2 回答 2

5

你有几个选择:

存根NetworkingProvider

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

// App

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

// Tests

myAppNetworkingProvider = NetworkStub()

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

这是大多数应用程序的最佳选择。您可以在Siesta 自己的性能测试中看到一个示例。它简单、快速并提供细粒度的控制,但仍然可以让您使用真实的 Siesta 行为进行测试。

存根网络

Siesta 与OHHTTPStubsMockingjayNocilla等网络存根库一起工作。(Siesta 本身使用 Nocilla 进行自己的内部回归测试,尽管该库具有内部竞争条件并且在撰写本文时维护得不是特别好,所以我不能全心推荐它。)

存根网络本身具有测试应用程序与底层网络 API 的完整交互的优势。这种方法可能最适合全面的集成测试,特别是如果您想记录和重放来自真实 API 的响应。

自定义资源协议

因为 Swift 支持追溯建模Resource所以不需要是(或实现)可测试的协议。您可以创建自己的一个:

protocol ResourceProtocol {
  // Resource methods your app uses
}

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

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

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

简而言之,与其他方法相比,它的价值更高。这当然不是进行回归测试的有效方法。

也就是说,如果您坚持纯粹的“不要测试超出边界”的单元测试理念,那么这就是实现它的方法。

于 2016-10-04T03:02:17.137 回答
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)
}
于 2016-10-17T12:53:20.377 回答