Unit Testing

AppCode 2.0 Released

JetBrainz has released a major update (2.0) to AppCode. I purchased my copy about 6 months ago, so the upgrade is free (anytime within 12 months).

The announcement says that Kiwi is now supported, so of course I needed to get a copy and check it out.

I’ve been wanting to redo the WhatsMySpeed code using true TDD with Kiwi, so I’m going to take this opportunity to try out AppCode 2.0 while I’m at it. I’m renaming it to HowsMyFuel to avoid confusion with the older code.

I’ve created a new public repository on GitHub to track this work. Feel free to watch and comment as I go. Since it is on git, you can use the git commit comments to monitor updates.

Accessing private methods and properties in ObjC unit tests

I’ve seen quite a few questions posted on various programming websites asking about how to access a class’s private methods from a unit test file. In Objective-C there are several ways to do this:

  1. Use performSelector in the unit test to access private methods
  2. Use Key-Value Coding to access properties and iVars.
  3. Define the methods and properties in a class extension.

I really like the 3rd approach the best. In case you aren’t familiar with class extensions in Objective-C, these are also known as anonymous categories.  The following example shows a simple class definition and implementation that includes a class extension:

// ExampleClass.h
// Public header file
#import <Foundation/Foundation.h>
@interface ExampleClass : NSObject {
}
// Publicly exposed methods
- (void)exampleMethod;
// Publicly exposed properties
@property (nonatomic, retain) NSString * exampleProperty;
@end
  
// ExampleClass.m 
// ExampleClass implementation 
#import "ExampleClass.h"   
@implementation ExampleClass 
// Properties 
@synthesize exampleProperty = exampleProperty_; 
// Methods 
- (int)exampleMethod {  
    // Do whatever this method needs to do... 
    return 3; 
}  

In this example, I’ve defined a class with an exampleMethod and exampleProperty. Both of these are declared publicly and so can be accessed easily from a unit test file as shown below:

// ExampleClass.m
// ExampleClass unit tests
#import <SenTestingKit/SenTestingKit.h>
#import "ExampleClass.h"

@interface ExampleClassTests : SenTestCase {
}
@property (nonatomic, retain) ExampleClass * testClass;
@end

@implementation ExampleClassTests
@synthesize testClass = testClass_;
-(void)testExampleMethodReturnValue {
    ExampleClass * ourClass = [[ExampleClass alloc]init];
    int returnValue = [ourClass exampleMethod];
    STAssertTrue( returnValue == 3, 
        @"Return value should have been 3 but was %d",returnValue);
}
@end

Now, what if you wanted to keep exampleMethod private, and not expose it in the public ExampleClass.h header file? As mentioned above, the unit test could use performSelector to execute the method, but this approach is limited to passing a single argument and precludes letting the compiler check your parameters, etc.

A better way is to declare exampleMethod in a class extension, and put that class extension in a separate header file. This file can then be imported into both the ExampleClass implementation file as well as any unit test files that need to access exampleMethod. This class extension header file is shown below.

// ExampleClassExtension.h
// ExampleClass Class Extension
// Declare any private methods and properties in this file.
// #import this file into the implementation file and unit test files.
@interface ExampleClass ()
- (int)exampleMethod;
@end

It’s just that simple. Using a class extension is considered a best practice for declaring your private methods and properties. Doing this makes it clear that these methods and properties are not intended for public use, otherwise they would be listed in the main header. But putting them in a class extension in a separate header file allows your unit tests to use them also. These methods and properties can be easily refactored, and will work correctly with autocompletion.

iOS Unit Testing

I’ve been knee-deep in iOS unit testing for the past few months. Xcode 4 has been a real blessing as well as a curse. Apple did a great job of integrating unit testing into Xcode 4, but so far has failed to provide much in the way of documentation. To make matters worse, things have changed drastically from Xcode 3. In the upcoming days and weeks I will be sharing what I’ve learned about unit testing in the new Xcode 4 environment.