Using Core Data to mock REST service in iOS app
Posted by Dan Nilsson on October 15, 2013

Quick link: https://github.com/BinaryPeak/core-data-mock-server

For some projects, it makes a lot of sense to separate yourself from being dependent on others deliverables. At Binary Peak we often find ourselves waiting for backend implementations to be completed when doing mobile applications. Mocking a REST service so all of the application flows can be tested before the application is done is usually a good strategy to deal with that. Sometimes the backend team will do that for us, but they are often under a tight deadline and stuff like this rarely gets prioritized.

A lot of teams choose to use services like Sinatra for this. An advantage with that approach is that writing the mock code in a language like Ruby will allow you to quickly get something up and running. We’ve used tools like that to great success before but this article will describe another way of doing it that suited a particular project we were doing.

The project

This project is an iOS application that uses Core Data entities to define its model objects. We wanted to be able to embed the mock REST server within the application so that it could always be in a demo state regardless of network connectivity. Key requirements were hooks that could trigger special conditions and functionality like random delays and error conditions.

We got the idea that the Core Data entity classes could be reused to create the mock server. If the mock object had a separate Core Data context, it could serve the client by encoding the entity objects directly to JSON. To do this there had to be a way of hooking into the requests so that they could be handled using our mock server instead of going through the network.

Intercepting requests

The application should do all of its network requests and flows like it usually does. Ideally the mock server should not be intrusive and impose demands on how requests should be done. We can accomplish this by changing the base URL to use a special protocol. For this example we use “mockserver”:

Normally the runtime won’t know how to handle these requests. To enlighten it, we need to install a custom NSURLProtocol.

MockServerURLProtocol.h

This class needs to be registered at application start up:

AppDelegate.m

Now, whenever a network request is performed using this protocol, our custom class will be consulted first. The class looks like this:

MockServerURLProtocol.m

Some of these methods doesn’t seem to do much, like canonicalRequestForRequest and stopLoading, but they must be implemented. canInitWithRequest determines if we should handle the request (if it uses the mockserver protocol). The heart of the code is in the startLoading method. Here we relay the response handling to our mock server class. The rest is basically some error handling and response encoding.

Setting up a mock server

One of the advantages of the mock server is that we get to reuse all of our model classes. Our setup uses a very slim Core Data context with no backing store inside the mock server. This basically means that two core data contexts are running simultaneously in the application.

Setting up such a simple context is straightforward. Here is how it’s done in our MockServer class:

MockServer.m

If you want you could create a more advanced setup that allows for saving and so on, but we found that it wasn’t really necessary as the solution is used only for testing.

Handling requests

The MockServer class relays requests based on the request string to various methods:

MockServer.m

A simple GET method may look like this:

MockServer.m

The MockServer uses NSDictionaries to create responses throughout the code and they are then encoded to JSON by the MockServerURLProtocol. A POST method may look like this:

MockServer.m

Bonus stuff

This kind of mock server can return results immediately, which can give a false sense of latency inside the application. People who have tried your mocked application will tend to be disappointed once the real service goes live. You will also forget to add activity indicators and stuff like that.

So we added a way to simulate network latency. If the MOCK_SERVER_DELAY is defined then that is used as a static delay. You could go further and introduce random errors and timeouts.

A big advantage of using a mock server is that you can easily trigger rare states and error conditions. Stuff that is documented in the API but rarely happens. For our project a special debug menu was added that was hooked up directly to the mock server. This made it possible to directly influence its behaviour from the app user interface.

The code

You can find a sample Xcode project with a complete implementation at:

https://github.com/BinaryPeak/core-data-mock-server

It’s used for a simple list based application with contacts. It implements one GET request and one POST request for creating new contacts.