A Networking Manager with Alamofire
Can you fully test this? YES WE CAN
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:
- You will be expected to be aware how to make a Single View Application in Swift.
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:

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.

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

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!).

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

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!)

Testing

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.

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

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

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:

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

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