Sunday, 11 January 2009

TDD Objective-C : Testing a Cocoa Framework Project

My intention is to write an iPhone application that does something simple, just so I can learn how they are designed, built, tested and deployed. The first step is to design the core functionality that the application will use. For that, I am creating a Cocoa Framework, which is a class library. This project will be test driven.

This describes how I created a Cocoa Framework project and the accompanying unit tests.

Operating System: Mac OSX 10.5.6
IDE: Xcode 3.1.2
Language: Objective-C


Creating a Cocoa Framework Project and Test Target

1. Start Xcode;
2. Go to File -> New Project... and create a new Cocoa Framework project named MyApp;
3. In this MyApp project under Targets, Add -> New Target... of the type Cocoa Unit Test Bundle called MyAppTests.

Making Your Target Dependent on the Main Executable

"When you configure your test target, you need to decide how you want that target to behave. The unit test bundles that come with Xcode can be integrated with your executable in one of two ways. One technique is to configure your test target as a separate entity that you build and run independent of your main executable. The other is to add dependencies to your target that automatically build your executable and run the tests each time you build." -- Xcode Help

I've chosen to run the tests every time I build the framework project, so I followed the steps on this Xcode Help page: To make your test target dependent on your framework project.

Here is a summary of how to make a Cocoa Unit Test Target dependent on your Cocoa Framework by establishing the dependency in your Xcode project:

1. Select your MyAppTests target;

2. Open an inspector for the target;

3. Select the General tab;

4. Add a dependency to the test target by clicking the + button and selecting the framework target MyApp from the list;

5. Select your Unit Test Bundle target;

6. Open an inspector for the target. To get an inspector on a project, just control-click on the test target and choose Get Info. The resulting window is referred to as an inspector. Typing Command-I does the same thing;

7. Set Build -> Linking ->Bundle Loader to $(BUILT_PRODUCTS_DIR)/MyApp.framework/MyApp;


Create a Test Class and a Failing Test

1. Control-click on the MyAppTests target and choose Add -> New File...;

2. Create a new Objective-C Test Case Class and name it MyAppFunctionalityTests. Two files will be created - MyAppFunctionalityTests.h (the declaration) and MyAppFunctionalityTests.m (the definition);

3. In MyAppFunctionalityTests.m, add a test method like this:


//
// MyAppFunctionalityTests .m
// MyApp
//
// Created by Damana Madden on 10/01/09.
// Copyright 2009 __MyCompanyName__. All rights reserved.
//

#import "
MyAppFunctionalityTests.h"


@implementation
MyAppFunctionalityTests

- (void) testThatThisIsTrueForThisCase
{
STAssertTrue(false, @"oops it didn't work.");
}
@end

4. To run the test, build the MyAppTests target. You will see this test fail.

Important: All tests must be prefixed with the word 'test' or they will not be picked up and run.

2 comments:

Matthew Wridgway said...

Hi and thanks for caring about TDD in Objective-C, do you have any more pointers for doing Inversion of Control or Dependency Injection? I guess protocols are the interfaces that one can use to abstract dependant classes from concrete implementations.. any help would be appreciated.

pablo said...

I believe OCMock is what you are looking for.

Acknowledge Me

Apple started a user experience trend many iOSes ago when it accepted Settings changes and did not ask for confirmation. Once the chang...