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