Welcome to Part 2 of my blog series about how to write tests when utilising modern language features like async/await or frameworks like Combine.
Part II Mocking like a Pro
Part III Unit Testing with async/await
Part V (interlude) — Implement your Data Access layer with Combine
Part II - Mocking like a Pro
I appreciate the fact that I’m writing a 6-part blog series about how to write tests, and with 2 posts down I still haven’t shown you a single test - but trust me that I’m giving you the tools to make the actual testing portion an absolute breeze.
What are mocks?
Mocks are versions of your classes and services which conform to the same protocol (interface) as the ‘real’ versions. These are dependency-injected into the classes which you’re testing and allow you fine-tune behaviour. You can do things like:
Count the number of times a method is called
Pass it some sample data to return for a success-case test
Tell it which error to throw to test your exception handling
We use mocks extensively when testing, to ensure that we can test the behaviour of the thing that we’re testing - in unit tests, we don’t care about the behaviour of the thing that we’re injecting.
Quick note on the Test Pyramid
The ‘Test Pyramid’ is an approach to testing:
Unit tests at the bottom of the pyramid - these usually only test one class, have lots of mocks, and we write a lot of them
Integration tests in the middle of the pyramid - these test the interaction between classes, and we should write a decent number for really critical components like our authentication or core business logic.
End-to-end testing at the top of the pyramid - these are a lot slower, test whole features at once, and we write a smaller number of these.
The mock-related thing to note here is that unit tests pretty much exclusively use mocks, whereas in integration tests you might use the ‘real’ version of a service that you inject, to test the real behaviour and interaction between the components.
How do we create mocks?
Creating mocks is pretty straightforward once you have an interface built.
Let’s return to our sample code for Bev. We’re trying to mock out the API, which in Part I we dependency-injected into the Repository class.
Remember, by mocking out the API we should be able to replicate the behaviour of the real API, but control all the results. Here’s the protocol (interface if you’re a fan of Kotlin) for the API:
To make a mock, let’s just define a class, MockBeerAPI, and you’ll see an error in Xcode:

Simply allow Xcode to auto-fill the method required to conform to the protocol, and hey-presto! You’ve got yourself a mock.

In true Art Attack style, here’s one I made earlier:
There’s quite a bit of extra power that I added to the mock - let’s go through it sequentially:
I added a
public initso that any test class can easily create their own version of this mock.There’s a public
stubBeersResponsethat returns aResulttype - this means I can tell my mock to return either an error or some test data when I set this property.The didGetBeersclosure isdeferred, which means it gets called after I return from mygetBeers()method. This is extremely helpful when dealing with async tests, but fairly advanced stuff which I'll cover in future posts.getBeersCallCountis a good old-fashioned integer property, that simply gets incremented every time thegetBeersmethod is called. This is great for writing the common or garden “did this method call this API” test.Finally, we modify
getBeers()to ensure we call the deferred closure, we increment the call count, and by usingget()we either return the value set in thestubBeersResponseResult, throws an error, or crashes if this isn’t set. In the sample code, I’ve actually written helper method called evaluate() which causes an XCTest failure instead of a crash if you forget to set this, but I’m leaving it out of this example for simplicity’s sake.





