I've recently been doing some iOS development, and working out the best way to test-drive the development of iOS apps was high on my priority list. I know that the automated testing of iOS applications is still not widely practiced and isn't well documented, so I decided to write a series of posts to start to rectify that. You may wish to read part 1 first.
Kiwi
We were looking for a testing framework which supported iOS’s asynchronous programming model and Kiwi answered the call. It has a great syntax, comprehensive set up assistance, asynchronous support and built in mocking. I’d highly recommend you check it out: the syntax helps me to think in the right way and it has pretty much all the features we needed.
Kiwi’s block syntax looks like this:
Much better than the old fashioned xUnit style of testing, in my opinion. You might hate it, of course. You can use Kiwi’s features without having to use the block syntax if you want.
Objective-C’s delegate model
Many of the Apple core libraries use a delegate pattern for handling callbacks from a class. This is similar to Java’s interfaces, and superficially similar to blocks in Ruby and anonymous functions in Javascript.
As an example, let’s take CoreLocation. When wanting to find the location of a phone, you create a new CoreLocationManager
and call startUpdatingLocation
on it:
This call returns immediately: so how do you execute code when the location is found? You use a delegate: an object with responds to the locationManager: didUpdateToLocation: fromLocation
method:
Then you set this object to be the CLLocationManager’s delegate before calling startUpdatingLocation
. Often you set the delegate to self
and define the delegate method on the calling object.
There’s more about this model in this article from Apple.
Testing delegates
This is tricky to test, because we can’t simply do this:
The test will call startUpdatingLocation
, and then immediately check the foundLocation
property to see whether it’s been set. It won’t have been, because the delegate won’t have been called yet.
How were we to stub endpoints such as the location system for for our app? We found two ways of doing this, with varying effectiveness:
- Using Objective-C categories to redefine class methods
- Using a Kiwi stub to inject a derived class which mocks out key methods
Next post, I’ll dive into some detail on both of these methods and show some of the pros and cons of each.
How are you testing iPhone apps? Do chime in throughout the series with suggestions and comments, and I’ll edit the posts as appropriate.
Check out my indie game Sol Trader, an epic space action adventure. Be part of a living society you can befriend, understand and manipulate to your own ends.
Follow