Unit Testing Tutorial for iOS: Xcode 4 Quick Start Guide

A unit testing tutorial for iOS and xCode 4. By .

Leave a rating/review
Save for later
Share
You are currently viewing page 2 of 3 of this article. Click here to view the first page.

Integrating GHUnit

OK, time to integrate GHUnit! It just takes three quick steps.

1) Add a GHUnit Test Target

First, we need to add a test target to our project for GHUnit. Select the project file in the Project Navigator view, and click ‘Add Target’.

Add new target in Xcode

Create an iOS View-based Application named ‘MyProjTests’ for the GHUnit target. As with the project creation, leave the “Include Unit Tests” checkbox unchecked.

2) Add GHUnitIOS Framework

The next step is to add the GHUnitIOS framework to our project. You’ll need to download it from github first if you haven’t already.

Note: Be sure you select the latest iOS version (named like ‘GHUnitIOS-####.zip’), and not the Mac OS X version (named like ‘GHUnit-####.zip’)!

We want to include the full set of files in our project, so unzip it into ~/myproj/MyProj.

Then select the “Build Phases” tab for the MyProjTests target, expand the “Link Binary With Libraries” section, and click the “+” button. Select “Add Other…” and select the GHUnitIOS.framework from the ~/myproj directory, as shown in the screenshot below.

Add GHUnit framework

Now verify that the test target builds before continuing. Select the iPhone Simulator for the MyProjTests target from the Scheme drop down and click the Run button. You will only see a blank view at this point in the simulator.

3) Configure GHUnit Test Target

The GHUnitIOS framework has an embedded window and app delegate, so we need to remove the ones installed by default when we created the test target.

First, delete the files MyProjTestsAppDelegate.h, MyProjTestsAppDelegate.m, MainWindow.xib, MyProjTestsViewController.h, MyProjTestsViewController.m, MyProjTestsViewController.xib, and main.m from MyProjTests.

Deleting unnecessary files to set up GHUnit

Second, remove the “Main nib file base name” property from MyProjTests-Info.plist.

Deleting entry for Main nib file base name

Next, download the file GHUnitIOSTestMain.m to ~/myproj/MyProj/MyProjTests, as shown in the screenshot below.

Downloading single file from github

Now, add the file to the MyProjTests target, making sure to select the MyProjTests target when adding the file.

Adding file to GHUnit tests target

Lastly, we need to update the build settings for the MyProjTests target. Select “Other Linker Flags” under MyProjTests and add the value “-ObjC -all_load”.

Adding Other Linker Flags for GHUnit

Congrats – you’ve successfully configured GHUnit! Run the MyProjTests target in the simulator and you’ll see the GHUnit test runner:

GHUnit setup with no tests

Creating a Simple Test Case

Although GHUnit is integrated in your project now, you don’t have any tests to run yet! So let’s make a simple test case to try things out.

Create a new Objective-C class SampleTestCase.m in the MyProjTests group, making sure it belongs to the MyProjTests target, but not to the MyProj target.

Our test case class does not need a header file, but Xcode 4 does not give us the option to only create a .m file, so delete the SampleTestCase.h file and replace the entire contents of the SampleTestCase.m with the following code:

#import <GHUnitIOS/GHUnit.h>

@interface SampleLibTest : GHTestCase { }
@end

@implementation SampleLibTest

- (void)testSimplePass {
	// Another test
}

- (void)testSimpleFail {
	GHAssertTrue(NO, nil);
}

@end

Then run the MyProjTests target in the simulator and you should see this:

GHUnit GUI with sample tests

You can tap the Run button in the upper right corner to run the tests – one should fail and one should succeed.

Creating a test case in GHUnit is straightforward, a test case is simply a method that follows these simple rules:

  • The class inherits from GHTestCase,
  • the method return type is void,
  • the method name begins with ‘test’,
  • and the method takes no arguments.

Obviously, to be a useful test case, it needs to do something (unlike the ‘testSimplePass’ method above.)

Each test case should have a single purpose, and often after all the setup is done it only checks a single value. It can be as simple as creating an instance of the class to be tested, calling a method on that class, and checking that the value returned matches your expectations.

Test cases specify what they expect by asserting certain conditions, and in GHUnit, there is a set of macros that cover a variety of cases in the file GHTestMacros.h. There are a few simple examples on the GHUnit website.

w00t! At this point you now have a working project using GHUnit on which you can build. Read on to learn how to add in OCMock support as well!

Addding OCMock

Now that we have GHUnit set up and running, we want to add support for OCMock. The framework available on the website does not work with iOS projects. We need the static library from the the example iPhone project and the header files from the framework.

Before we get started, go ahead and create a separate directory in our project to hold the library and header files.

From the Project Navigator in Xcode, right click on MyProj and select “Add Files to ‘MyProj'”:

Adding new folder for libraries

Select the directory ~/myproj/MyProj, and click the “New Folder” button. Add a folder named “Libraries” and click the “Create” button. Once the folder is created, click ‘Add’ to add it to the target.

Now that we have a folder ready to add OCMock into, let’s get started! Again, adding OCMock into your project is just three steps.

1) Install latest OCMock iOS library

First download the file libOCMock.a to the ~/myproj/Libraries directory.

Then right click on ‘Libraries’ folder in the Project Navigator, and add the libOCMock.a file to the MyProjTests target.

2) Extract header files from OCMock framework

Download the latest ocmock dmg file from download directory to the ~/myproj directory and open it in finder. It should mount the image “OCMock #.##” in finder.

Select the directory ‘Release/Library/Headers/OCMock’ directory and add it to our project ‘Libraries’ folder (for the MyProjTests target).

Copying OCMock header files

The end result in the Project Navigator should look like this:

OCMock header files added to Xcode

3) Update build settings for MyProjTests

The following linker settings depend on the fact that the above step created a physical directory ‘OCMock’ under our directory ‘Libraries’.

In the “Build Settings” for the MyProjTests target, make sure the “Library Search Paths” contain the “$(SRCROOT)/Libraries” directory like this:

Adding library search path for OCMock

Next, we need to add “$(SRCROOT)/Libraries” to the “Header Search Paths” item. Make sure you check the ‘Recursive’ checkbox as well:

Adding header search paths for GHUnit

Simple Test Case with OCMock

Now we need to add some test cases that use OCMock to our SampleTestCase. Update SampleTestCase.m to look like this:

#import <GHUnitIOS/GHUnit.h>
#import <OCMock/OCMock.h>

@interface SampleLibTest : GHTestCase { }
@end

@implementation SampleLibTest

- (void)testSimplePass {
    // Another test
}

- (void)testSimpleFail {
    GHAssertTrue(NO, nil);
}

// simple test to ensure building, linking, 
// and running test case works in the project
- (void)testOCMockPass {
    id mock = [OCMockObject mockForClass:NSString.class];
    [[[mock stub] andReturn:@"mocktest"] lowercaseString];

    NSString *returnValue = [mock lowercaseString];
    GHAssertEqualObjects(@"mocktest", returnValue, 
        @"Should have returned the expected string.");
}

- (void)testOCMockFail {
    id mock = [OCMockObject mockForClass:NSString.class];
    [[[mock stub] andReturn:@"mocktest"] lowercaseString];

    NSString *returnValue = [mock lowercaseString];
    GHAssertEqualObjects(@"thisIsTheWrongValueToCheck", 
        returnValue, @"Should have returned the expected string.");
}

@end

And finally, run the MyProjTests target in the simulator and it should look like this:

Sample test for GHUnit and OCMock

The tests we added that use OCMock merely demonstrate we have the project configured correctly. They do not show the usefulness of mock objects or the OCMock framework.

Mock objects are useful in testing that a class interacts with other objects properly, without the need to configure a large object hierarchy, and in some cases before a class is even implemented.