Stubbing AFNetworking Calls In XCode Unit Tests


A unit test by definition of testing the smallest possible part of the application, should eliminate all dependencies from the systems its interacting with. This in turn will remove any unknown or variable outcomes from the tests, focusing on the isolating the specific code you’re interested in. In the case of networking calls, it is unideal for tests that deal with the (un)marshalling of data to depend on the network. Therefore a stubbing library is needed.

OHHTTPStubs to the Rescue!

Luckily there is a great library to do just what we need here – stubbing out some network calls – called OHHTTPStubs.

Because these tests are asynchronous, the network requests are sent in a separate thread or queue different from the thread used to execute the test case. So you’ll have to ensure that your unit tests wait for the requests to finish and their response arrived before performing the assertions in your test cases. Otherwise your code making the assertions will execute before the request had time to get its response.

OHHTTPStubs includes a custom AsyncSenTestCase subclass of SenTestCase that provides methods like waitForAsyncOperationWithTimeout: and notifyAsyncOperationDone. We can utilize these methods in our test cases.

A Networking Stub

Most people are using the AFNetworking library so this example will show a test using that.

In this case I’ve created a network wrapper that allows turning stubs on and off. The request here happens to be mocking XML data, but JSON follows the same pattern. This is an implementation of a class called GrillNet that has two functions:

The two functions are: stubsOn to activate the stubbed networks calls, and getGrillStatusWithURL which invokes a network request. If we call stubsOn before the getGrillStatusWithURL call is made, it will invoke the stub and return the mock data which I’ve generated and put into the file cyberq.xml.

Notice that getGrillStatusWithURL implements a success and failure callback. Thus I’ve created a protocol to respond to the two scenarios which asks for optional implementations of notifyDone and notifyDoneWithData:data, shown here:

Our tests can implement this protocol to assist with the notifying that our asynchronous operation is done by calling notifyAsyncOperationDone. The class GrillzTests subclasses AsyncSenTestCase and implements GrillNetActionProtocol.

And in this same class we can implement notifyDone and notifyDoneWithData:data. They will both call notifyAsyncOperationDone from AsyncSenTestCase but notifyDone is only called on failure when no data is returned, while notifyDoneWithData:data is invoked when the request is successful .

Therefore it is the job of notifyDoneWithData:data to do something with this data. In this case we are setting the values in a GrillStatus object that was used in the test assertion comparing the value in _gs above.