A Networking Manager with Alamofire

Can you fully test this? YES WE CAN

Image for post
Image for post
Photo by Jesse Roberts on Unsplash

I’ve previously written a network manager with the intention of testing it completely. Can I do the same using Alamofire? That is, test the requisite classes without making real network calls?

Read on to find out!

Difficulty: Beginner | Easy | Normal | Challenging
This article has been developed using Xcode 11.4.1, and Swift 5.2.2

Prerequisites:

What the project is, and what it isn’t

The idea of this project is to create a usable network manager using Alamofire, and more than that actually testing the manager, in a similar way to the method I used to create a network manager using urlsession in a previous article.

That means that the View Controller accesses the Network Manager directly simply for ease of creating this tutorial (it is not about architecture!). If you want to learn more about the architecture I might use, tyr this article about MVVM-C that contains a full example — I usually choose to make the network requests from the View Model but you might choose to make these from the coordinator.

The motivation

When I usually create an Alamofire project the request seems all very simple. I'd ususally use Af.request() and it would look something like the following:

Image for post
Image for post
Click for Gist

which seems great. But how can we inject a urlsession instance into there? It seems impossible?!?

So let us get started!

The approach

The Alamofire dependency

There are many ways to add Alamofire as a dependency. I’ve created a full guide to this HERE but the short version is that I’ve whacked https://github.com/Alamofire/Alamofire.git to import a new package up to next major version (Using Semantic Versioning).

The Alamofire router

Alamofire has a router in order to compile URL Strings and apply headers. The advantage to using this router is that headers can be put in-place. It sounds fantastic, but I think of this as roughly equivalent to my method of building URLs in Swift.

Like a good Swift progammer I’m going to make this conform to a protocol

so let us see this protocol, which I’ve called APIRouter: note that this file needs to import Alamofire as it uses several types included in the third-party framework.

Image for post
Image for post
Click for Gist

We then create a concrete type that conforms to this protocol, I’ve called this JSONPlaceHolderAPIAction because I like catchy names

Image for post
Image for post
Click for Gist

Now for fun, (and since testing is always worth doing) I’ve developed the following (rather simple) test. Of note here is that I’ve imported XCTest and Alamofire, but here is the whole file (it passes!).

Image for post
Image for post
Click for Gist

Wonderful!

Now for later use I’m going to create a Mock version of the router that can be used later on

Image for post
Image for post
Click for Gist

The overall strategy

Usually I’d think about injecting a Session instance which could then be replaces during testing using Dependency injection. However, overriding Session just to inject a URLSessionMock isn't really the strategy that the makers of Alamofire seemed to have in mind.

We can do better

The implementation

The Network Manager

This is going to work with a protocol too (how awesome!)

Image for post
Image for post
Click for Gist

Testing

Image for post
Image for post
Click for Gist

The ViewController

Yes, you would never do this in production. Yes, you need to handle the errors that are given from the network operation. Yes, we are accessing the NetworkManager straight from the view controller.

In any case, here is my method of creating a View Controller.

Image for post
Image for post
Click for Gist

Testing

Now this, of course needs to be tested. There are two possible tests here — I can use the implementation version of the router or the mocked version of the router.

In practice the two are the same because we set the result in a URLProtocolMock which (in my implementation) does not care about the router.

How does that look?

Let us take a break for the URLProtocolMock instance.

The URLProtocolMock

Image for post
Image for post
Click for Gist

we then have the option (within our tests) of using an instance of URLProtocolMock to create

Image for post
Image for post
Click for Gist

which gives us the session that can then be injected into our NetworkManager instance

Awesome.

Back to testing

We can inject the URLProtocolMock using the ViewController - no problem - here is the excerpt of the test:

Image for post
Image for post
Click for Gist

This suceeds, so what about a similar test that will fail? As the requestHandler is a computed property we can just make it throw!

Image for post
Image for post
Click for Gist

Fantastico!

Conclusion

The approach taken is rather different than that for a simple URLSession, but it is worth going through this exercise to make sure you NEVER call a real API while testing.

I mean never.

I hope this article has been of use to you, and that you have enjoyed reading it.

The code from this is included in the attached Repo.

If you’ve any questions, comments or suggestions please hit me up on Twitter

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store