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?
You have several options:
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.
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.
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:
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.
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)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With