Unit Testing Patterns for Asynchronous Networking Communications

Thu Oct 10 2013 | Mark Struzinski

---

A common issue I always run into is how to test asynchronous methods,
especially networking calls. I used test the result of the calls, such as the
parsing of return data, because testing the entire method proved impossible.
I recently read an article from the excellent objc.io
publication on asynchronous testing. By combining the patterns used in this
article with some refactoring, I finally have my networking code under unit
tests.

Here’s what I did:

Architecture

First, I will detail how my app was architected prior to setting up unit tests.
I use AFNetworking to handle all API calls, and make use of the
AFHTTPClient to centralize all calls to a specific base URL.
The HTTPClient would be a singleton, and each service call would be passed a
typed return block to execute on completion or failure.

This same pattern is used each time I want to make a call into my API, and a
new call is set up for each endpoint. The pattern works well, and has proven
itself useful. However, it always felt like the APIClient class was doing a
little too much work, and had too much knowledge of the internals of parsing
the JSON data returned. This proved to be true once I attempted to apply tests
to these methods.

Building the Tests

The first lesson learned: always test and code at the same time
(preferably in that order)! This is about the tenth time I have told myself
I was too time constrained to write tests while I was coding. In hindsight,
it usually means I’ll be doing some heavy refactoring after I start writing
tests. The tests always show that the code I wrote quickly is too
interdependent, and needs to be broken down more into logical components.

In order to separate concerns and to facilitate mocking data parsing responses,
I began to move data parsing code and logic into a separate helper class. This
class would be responsible for the following:

Parse the JSON response

Report success ior failure

Create and populate data model objects out of the response

Save the objects to core data

Return core data object(s) from the call after parsing and saving is complete

So with that in mind, the above code changes implementation to look like this:

This allows me to mock the DataProcessingManager object and tell it what to
return. Putting this all together, I now have a way of testing asynchronous
API calls with test data and validating that my networking calls are doing the
right thing in response to different scenarios.

After this change, one of my tests against this networking call would look
like this: