Mocking gesture recognisers with OCMock

Full credit for this tip goes to my colleague, Tom Kelly.  He doesn’t have a blog at this point, so I figured I’d blog the tip for him.

You can mock gesture recognisers like any other type of object.  Its not something I’d considered before, but this means that you can unit test gesture handling functionality on your classes by calling their gesture handling methods and passing your mock gesture recogniser.

Below is an example of a mock tap gesture recogniser:

id gestureMock = [OCMockObject partialMockForObject:[[UITapGestureRecognizer new] autorelease]];
[[[gestureMock stub] andReturnValue:OCMOCK_VALUE(CGPointZero)] locationInView:[OCMArg any]];

Then, in your unit test, you call the tap handler on your class under test:

    // Set up control under test here...

    // Create the mock tap gesture handler
    id gestureMock = [OCMockObject partialMockForObject:[[UITapGestureRecognizer new] autorelease]];

    // Expect:
    [[[gestureMock stub] andReturnValue:OCMOCK_VALUE(CGPointZero)] locationInView:[OCMArg any]];
    // Set up any expected behaviours on your custom class here...

    // Call the tap handler method on your custom class here...

Automating unit tests in XCode

I’m currently working on an iOS project.  Within the project we have a set of application unit tests.  We are using the Jenkins CI service to automate builds of our product.  We have written a build script, which Jenkins runs once it has checked out our code.  As part of the shell script, we would like to run the unit tests in the project as well, to make sure that the commit hasn’t broken anything.
The steps we have followed to achieve this are based on this excellent blog post:

By adding this line to our build script:

xcodebuild -target unitTestBundleTargetName -configuration Debug -sdk iphonesimulator5.1 TEST_AFTER_BUILD=YES clean build

and patching the /Developer/Platforms/iPhoneSimulator.platform/Developer/Tools/RunPlatformUnitTests file as described in the blog post above, we are able to run our unit tests.

That’s not quite it though.  We’ve updated to use XCode 4.5, which now includes the simulator for iOS6.  There are problems with iphonesimulator6.0.  If you update the line above to use iphonesimulator6.0, you will get the following error:

Unknown Device Type. Using UIUserInterfaceIdiomPhone based on screen size
Terminating since there is no workspace.

This isn’t a problem for us, as we’re not using iOS 6 features. However, if you are, and you need to run the iphonesimulator6.0, then I can imagine this will be a major issue.

I’m going to have a little rant at this point.  It is just good practice to use a continuous integration environment to produce your builds.  One of the prerequisites for this is being able to run and test your builds from the command line.  XCodebuild gets you some of the way, in that it will create a build for you, but it feels wrong that developers are having to patch the Apple developer tools in order to be able to run their unit tests from the command line.  And even if they do, they are not currently able to test iOS6-specific features.

XCode is a powerful tool, but it feels like Apple should be doing more to support good practice like continuous integration.  Coming from a Java background, where this kind of thing is well supported, it is surprising that it is not so in the iOS world.