Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I mock resource responses?

Tags:

siesta-swift

In my app I have a class that encapsulates a Service and has methods that return resources and requests. In my tests I want to mock success/failures for the requests and resources without making any real network calls.
Since Request is a protocol, it is easy to do this by returning a custom implementation that just calls onSuccess, onFailure etc.

However, it is not that simple for the methods that return a Resource, since Resource is a final class and not a protocol.
I want to create a mock Resource that doesn't do any real network requests when load() etc is called, and exposes some way to fake a success/failure that triggers the observers added to the Resource.

Is there any way of doing this at the moment?

like image 246
user6914425 Avatar asked Oct 03 '16 08:10

user6914425


2 Answers

You have several options:

Stub the NetworkingProvider

Create your service with a custom NetworkingProvider implementation.

// App

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

// Tests

myAppNetworkingProvider = NetworkStub()

Your StubbedNetworkingProvider can return a single hard-coded URLResponse, or match on URLRequest if you want to stub multiple responses at once.

This is the best option for most apps. You can see an example of it in Siesta’s own performance tests. It’s simple, fast, and gives fine-grained control, but still lets you test with realistic Siesta behavior.

Stub the network

Siesta works with network stubbing libraries like OHHTTPStubs, Mockingjay, and Nocilla. (Siesta itself uses Nocilla for its own internal regression tests, although the library has internal race conditions and is not especially well maintained as of this writing, so I can’t wholeheartedly recommend it.)

Stubbing the network itself has the advantage of testing the full interaction of your app with the underlying networking API. This approach may be best for full-on integration tests, particularly if you want to record and replay responses from a real API.

Custom Resource Protocol

Because Swift supports retroactive modeling, Resource doesn’t need to be (or implement) a testable protocol. You can create one of your own:

protocol ResourceProtocol {
  // Resource methods your app uses
}

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

This sounds the most like what you’re looking for in your original question. However, I don’t especially recommend it:

  • It’s the most complex to implement — and the most error-prone. You’ll find it surprisingly difficult to accurately mimic all of Siesta’s behavior. Trust me: the Resource API seems innocent enough at first, but you’ll find yourself reimplementing half the library if you try to exercise your whole app this way.
  • It’s likely to miss problems and not catch regressions. Many of the dangerous spots using Siesta have to do with the exact sequence of calls: which events happen and in what order, what happens immediately vs. on a subsequent turn of the main run loop, what observer/owner relationships do or don’t create retain cycles, etc. You’ll have to make assumptions about all these things, and you’ll end up testing your code against your assumptions — not against the library’s real behavior.

In short, compared to the other approaches, it’s higher effort for lower value. It’s certainly not an effective way to do regression testing.

That said, if you are adhering to a purist “don’t test past the boundaries” unit test philosophy, then this is the way to do it.

like image 60
Paul Cantrell Avatar answered Nov 08 '22 02:11

Paul Cantrell


I'm in the process of writing an app which uses Siesta, and I've been using URLMock to mock out the network requests which Siesta makes. I've been happy with the result (it just does what I want without a lot of fuss), but I'm sure the other libraries would work too. I recommend working with a network mocking library, they have features you may not think of right away, such as setting it up to return an error if the test makes unexpected network requests.

Here is how I setup URLMock to work with 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)
}
like image 1
Jordan Wood Avatar answered Nov 08 '22 03:11

Jordan Wood