In this unit testing screencast for Swift developers, we explore how to use Test Driven Development to verify method calls.
Getting Started Guide
If you’re new to unit testing or are trying to get set up with unit testing in a Swift project, you might check out my getting started guide before jumping into the screencast.
GitHub repo of the example developed in the screencast.
Hi, I’m Andrew from andrewcbancroft.com, and I’m bringing you a test driven development example for iOS in Swift.
The goal of this video is to teach you how to write a unit test to verify that a method was called.
I’ll begin in Xcode 6.1.1 with a side-by-side view of my TestCase class, and my primary View Controller class. This is what Xcode generated for me when I chose to create a new Single View Application.
Imagine a scenario with me: Suppose that as part of your application’s requirements, you mush show an Alert View after your primary view loads. How would we go about using Test Driven Development to implement this “feature”?
Well, we’d write a test, of course – I’ll name it something appropriate like “testUIAlertViewShowsAfterViewLoads”
Next, I need to create an instance of my ViewController class so that I can test it.
But immediately, I run into trouble. It seems that my TestCase class can’t “see” my View Controller class.
Thankfully, it’s a simple fix: Simply add the View Controller class to your Test target.
With everything compiling now, we can move to the next line of test code.
First off, in order to test my View Controller’s Alert View functionality, the Alert View has got to be visible to my test. The easiest thing for me to do at this point is to assume that there will be a property on my View Controller that I can set. This allows me to perform a kind of dependency injection known as “setter injection”. All it really means is that the property is dual-purpose. When the app runs on my iPhone, it’ll use a real UIAlertView. But when I run it in my tests, I can plug in a UIAlertView that I control the behavior of, so that I can verify what I need to in my tests.
The ability to swap in a kind of Alert View that I control really is the “magic sauce” to this whole test-driven operation. In order to know whether or not a UI element was “shown” in a unit test without actually showing something on the screen in a simulator or device, I need to invent something known as a test-double. A fake object, if you will.
My Fake Alert View will have some special capabilities that allow me to know whether the “show()” method was called on it. At the same time, it needs to be able to be substituted in my View Controller for a real UIAlertView.
Since Swift supports object-oriented design, we have inheritance at our disposal here.
I’ll create a nested class inside my test function called FakeAlertView. Notice that it’s a subclass of UIAlertView. What’s great about this is that it meets both of my testing requirements: I can control it’s behavior, and it can be substituted anywhere a UIAlertView is needed.
I’ll finish fleshing out this fake object in a minute. Now that Xcode isn’t complaining about not knowing what a FakeAlertView is, I’ll turn my attention to a new compiler complaint: I don’t have an alertView property on my View Controller yet, so I’ll add one.
There’s just a little more setup that’s needed in order to be able to verify that the show method was called. Since show() doesn’t return anything, we need some way to know that its logic was executed. I’ll do two things to expose this:
- I’ll have a boolean property called showWasCalled on my FakeAlertView that is initially set to false.
- I’ll override the show() method in this fake UIAlertView subclass. Inside the method body, I’ll reassign the value of showWasCalled to true. That will be enough for me to use inside an XCTAssert, which is coming up.
We’re nearing the finish line here. All that’s left is to call my View Controller’s viewDidLoad method, and write my assertion.
The only thing I’d tell you to make note of is that we need to cast the View Controller’s UIAlertView instance to a FakeAlertView so that we can access the showWasCalled property.
Running the test at this point should produce a failing test, which is exactly what we want (because there’s no code that calls the alertView’s show() method in viewDidLoad()).
The last step to this adventure is to write the production code to pass the test. In viewDidLoad, I call my alertView’s show method and re-run the tests.
And we’re green! Which means we’ve managed to successfully verify that a method was called.
Thanks for watching – I have other resources related to Swift and iOS development at andrewcbancroft.com.