The days of the Massive View Controller are long gone. With Swift, there are so many different ways you can make your code more modular and more testable. You can use MVVM, helper objects, and more recently, protocol extensions. Some of you may be new to protocol extensions or unit testing. You might be wondering how to get started with iOS Testing for Protocol Extensions. After all, protocols are neither class nor struct. You can’t simply instantiate them and start writing tests. In this simple tutorial, I will show you how to test protocol extensions in your Swift app.

This is a pretty lengthy tutorial. Feel free to follow along. You can also Download The Example Project Source Code on Github

Step 1.) Define your protocol.

We are going to create an example project where we will define a simple error type and a protocol that can turn the error into a basic dismissable Alert Controller. You will definitely want to check the “Include Unit Tests” box when setting up your project.

errorAlertExampleSetup


Once your project is setup, you will want to add a blank Swift file. This is where we will define the protocol and protocol extension that we want to test. The code below defines a protocol, “ErrorAlertRepresentable” that you can apply to any error type. As long as you define the alert message property, you can access a generic UIAlertController with an O.K. button to show your alert.

So now that we’ve got both a protocol and a protocol extension to test, let’s test that our protocol extension works as we would expect. Now I know some of you might think we would want to create an error type to conform to the protocol first, but that’s not really necessary. We can create a mock object, like a struct, and then we can make our mock conform to the protocol. The beautiful thing is that our mock can stay simple, even if everything else that implements the protocol in the app happens to be complex. Simple mocks like this are essential when doing iOS Testing for Protocol Extensions.


Step 2.) Create a struct or a class that conforms to your protocol.

This is something you will do in your test target. So go ahead and click File -> New File -> Unit Test Case Class to create a new Unit Test Case.

ErrorAlertRepresentable


The default class you’ll get from Xcode will look like this:

You can get rid of the testExample() and testPerformanceExample() methods. They’re just stubs for beginners. You will also want to import your app module using the @testable directive. This gives your unit test target access to the project files you plan to test. After you make those changes, your blank test case should look like this.

Now we are ready to go to work. Within your test case class, you will want to define a struct that conforms to the protocol you want to test. You can call it anything you want. I usually call mine “SUT,” which is shorthand for System Under Test. You can also use the same name in lowercase for the instance of SUT that you plan to test. Putting all of it together, you get something like this:

You might be wondering why we’re giving our instance a bang and declaring it as an implicitly unwrapped optional. I do it to ensure that the same instantiation logic gets called at the beginning of each test and also to ensure that any previous state gets cleared at the end of each test. It’s really up to you though. You could use a let and declare it as a constant as well. Now that we’ve setup the protocol-conforming struct that we want to test, we can begin to write our tests!


Step 3.) Write your tests against your locally-defined entity.

In our case, we only have two tests we are interested in. First, we want to know that we can create a basic alert action to dismiss the alert, and that said action reads “O.K.”. Second, we want to know that the alert controller we create has the same title as the alert message property on our struct and that it uses the “generic okay action” we have defined in our protocol extension. Here is one way to test that:

If you run these tests, you will see that they pass. Although you can’t directly compare the generic okay action using XCTAssertEqual, you can compare the properties to make sure they match. You also may have decided to implement something like the generic okay action somewhere else. In that case, you’d simply call it from wherever else you had defined it (usually as a class var or a class extension on UIAlertAction).


Using your tested protocol extension in the real world

We’ve done all of the hard work to incorporate iOS Testing for Protocol Extensions. Now we can build our sample app using a real error type that conforms to our protocol. Here’s an example of a kind of error you might run into. Let’s say you are trying to figure out if something is Rick Astley. So long as the thing never gives you up, never lets you down, never runs around, or deserts you, you have a valid Rick Astley on your hands (leaving aside, of course, the possibility that your object might make you cry, tell a lie, say goodbye, or hurt you). As you go through your Rick Astley validation process, you generate errors whenever your object fails to meet one of these conditions. Your error class might look like this:

Now we’re going to define a basic validation function in a separate validator object. If you’ve used try-catch in Swift, this should look pretty familiar. We aren’t going to create anything fancy, just a simple function that takes a few boolean parameters. It throws an error whenever the object isn’t Rick Astley.

Guard statements are really useful here. They make our validation logic super concise! Whenever our “potential romantic partner” object fails to meet any criterion that would make it Rick Astley, we immediately throw an error. Now that we have our validation logic, we are going to hook up a view controller with a few UISwitches and a simple “validate” button that runs our validation logic. If one of the Rick Astley errors is thrown, we can use the new property we get from our unit tested protocol extension to display the alert. Here’s an example of how you might bring this logic into a controller.

As switches get toggled, various properties of our “Potential Romantic Partner” object change along with them. When we want to validate our romantic partner, we run a try-catch block. If we happen to catch a Rick Astley error (the error type that now conforms the protocol in our unit tests), we display the “basicAlertController” property of that error. If the validation passes with zero errors thrown, we show the “It’s Rick Astley” alert.

Simulator Screen Shot Jul 11, 2016, 8.29.55 PM

That’s pretty cool, but do you want to know what’s even cooler? You get this error alert functionality with any new error type you define. So long as you make the new error type conform to the “ErrorAlertRepresentable” protocol, the alert controller is yours! Plus, because you wrote unit tests for your protocol and protocol extension, you know it’s going to work every time. It might seem like a bit more effort to do iOS Testing for Protocol Extensions, but I guarantee you the effort is well spent. Good tests, like Rick Astley, will never give you up, never let you down, never run around, or desert you.

iOS Testing for Protocol Extensions – Source Code

All of the project files in this article are available for free: Example Project on Github