Home
subscribe

L'etat, c'est moi

Mere Complexities sells the consulting and development services of me, Paul Wilson.

Conferences

Organising Scotland on Rails
Speaker, RailsConf Europe '08

Archive

iPhone TDD using Google Toolbox and iphone_testify

Previously, we’d decided to switch from using Rbiphonetest to using Google toolbox for Mac code. It’s about time we got started.

To begin with we’ll just set up an iPhone project for testing. This will include automatically running all the tests every time – just like autotest.

Setting up the files

Of course you’ll need to be running OS X 10.5 (Leopard) and the latest iPhone SDK.

Fire up XCode and create an iPhone OS project. (For the purposes of this example it doesn’t matter what type; a Utility app is as good as any). I’ve written a Ruby Gem to help getting all the files in place, so we may as well use those. From the terminal go to your new application directory.

First we’ll install the gem. If you haven’t already you will need to to add github as a gem source. (If you can’t remember just enter gem source and see if github is listed).


sudo gem update --system
gem source -a http://gems.github.com

Either way, install the gem.


sudo gem install paulanthonywilson-iphone_testify

Then run the iphone_testify command.


iphone_testify

This adds the google unit testing code to the google_testing directory, creates a directory for the UnitTests. There’s also a Rakefile_ and an autoiphonetest.rb, and we’ll get round to those later.

Setting up XCode

There’s a few things you need to do in XCode. The gem doesn’t do this yet, but I’m working on it.

Create a new Target called Unit Test. Right click on Targets in the left pane. Choose an “iPhone OS” Application target and call it “Unit Test”.

adding an xcode target

Right click on the Unit Test target and choose “Add—> Existing Files”. Select all the files in the google_testing directory (or at least all the .h and .m files).

add google files

(If you’re feeling tidy, which I hope you are, you probably want to add these to a “google_testing” group as well.)

Right click on the Unit Test target again, to add a “new run script build phase”.

add new build phase

Set the script to be google_testing/RunIPhoneUnitTest.sh.

build phase run script

Add a group in which to keep your unit tests. Right click on the group and set the path to be UnitTests, so that the test classes will go where we expect on the file system.

unit tests group

That’s all a bit of faff. I am hoping to automate the xcode part: you can stay tuned by watching iphone_testify on Github.

Write a test

Let’s write a dummy test, just to get us started. Right click on your UnitTests group and add a new file (iPhone OS Cocoa Touch Classes – NSObject subclass). Let’s call it BlahTest.m. Add it only to the Unit Test target. Uncheck “Also create BlahTest.h”: you don’t need a header.

adding dummy unit test

Edit the BlahTest.m to extend SenTestCase:-


#import "../google_testing/GTMSenTestCase.h" 

@interface BlahTest : SenTestCase
@end

@implementation BlahTest

@end

Note that we’ve included the interface definition in the implementation file: there’s nothing to stop you using a separate header file, but there’s not a lot of point. Let’s add a failing test.


@implementation BlahTest

-(void) testSomething{
    NSString *actual = @"hello matey";
    STAssertEqualStrings(@"hi mate", actual, nil);
}

@end

Run through XCode

The tests are ‘run’ as part of the build and failures are reported as build failures. In XCode set the target to “Unit Test” and build.

failing test in xcode

Run through Rake and autoiphonetest.rb

Running iphone_testify also provides you with a Rakefile for building/running the test target. From the command line in your project directory just run


rake

failing test in rake

Even better, run


./autoiphonetest.rb

This will build/run the unit tests evertime a change is detected in the Classes or UnitTests directory. The automatic running of unit tests does wonders for flow.

The rake and autoiphonetest.rb builds will inform you of the state of the tests using Growl: to take advantage of this you will need to have Growl and growlnotify installed. In order to work around a bug in growlnotify, you need to enable “Listen for incoming network connections” in the Network pane of the Growl System Preferences.

Now we’re set up running with autoiphonetest.rb, let’s fix our test and see our pass notification; I’ll leave the test fixing as an exercise for the reader.

passing

That’s it for now. In our next instalment we’ll look at building up or Twitter application using Objective-C unit tests.

Update: Corrected a couple of bugs:

  • The target must be called Unit Test (not Unit Tests) to work with my gem
  • I ought to have used STAssertEqualStrings for comparing strings (not STAssertEquals).
All