Saturnboy
 8.16

Sometimes I feel like I write more test code than real code. For unit tests on iOS our stack is OCHamcrest, OCMock, and GHUnit. For functional tests, there’s nothing better than FoneMonkey. For this post, I’m going to focus on OCHamcrest.

Hamcrest was born in the Java world as the matcher framework in jMock. It was quickly extracted into its own framework and has become somewhat of a monster in the testing world. It’s now included directly in JUnit (since v4.4), and has been ported to many languages (OCHamcrest in Objective-C, Hamcrest-AS3 in Actionscript, PyHamcrest in Python, etc.). Additionally, the matcher concept is generally useful, and Hamcrest is used is lots of different places (my favorite is collection filtering with Hamcrest in LambdaJ).

When writing unit tests, OCHamcrest offers lots of advantages over the vanilla SenTest assertions. First, there’s a ton of matchers that really make life easy, especially when testing collections like NSArray. Second, OCHamcrest matchers are very readable in code, almost self-documenting. Lastly, OCHamcrest automatically provides excellent failure messages when actual is not equal to expected.

Matching Strings

Some string matching examples:

  • is – match the complete string
  • startsWith – match the beginning of a string
  • endsWith – match the end of a string
  • containsString – match part of the string
  • equalTo – match the complete string
  • equalToIgnoringCase – match the complete string but ignore case
  • equalToIgnoringWhiteSpace – match the complete string but ignore extra whitespace (new line, tab, or double spaces)
NSString *s = @"FooBar";
 
assertThat(s, is(@"FooBar"));
 
assertThat(s, startsWith(@"Foo"));
assertThat(s, endsWith(@"Bar"));
assertThat(s, containsString(@"oo"));
assertThat(s, equalToIgnoringCase(@"foobar"));
 
assertThat(@" X \n  Y \t\t  Z \n", equalToIgnoringWhiteSpace(@"X Y Z"));

NOTE: Technically, is isn’t really a matcher, it’s a matcher decorator that implicity converts to the equalTo matcher. [thanks Jon!]

Combining Matchers

You can combine multiple matchers with:

  • allOf – AND together all matchers
  • anyOf – OR togehter all matches
NSString *s = @"FooBar";
 
assertThat(s, allOf(startsWith(@"Foo"), endsWith(@"Bar"), nil));
assertThat(s, anyOf(startsWith(@"Foo"), startsWith(@"Bar"), nil));
assertThat(s, anyOf(endsWith(@"Foo"), endsWith(@"Bar"), nil));

NOTE: The list of matchers must be nil terminated.

You can invert a matcher, or multiple matchers, with:

  • isNot – negate the matcher
NSString *s = @"FooBar";
 
assertThat(s, isNot(@"foo"));
assertThat(s, isNot(endsWith(@"Baz")));
assertThat(s, isNot(allOf(startsWith(@"Baz"), endsWith(@"Baz"), nil)));
assertThat(s, isNot(anyOf(startsWith(@"Baz"), startsWith(@"Baz"), nil)));

Matching nil

You can match nil with:

  • nilValue() – stands in for nil
  • notNilValue() – stands in for !nil
NSObject *o = nil;
assertThat(o, nilValue());
 
NSString *s = @"FooBar";
assertThat(s, notNilValue());

Matching Classes

You can match an instance’s class with:

  • instanceOf – match the class
NSString *s = @"FooBar";
assertThat(s, instanceOf([NSString class]));

Matching Numbers

One of the great pains of Objective-C is typing numbers from primitive types to objects and back again. OCHamcrest has a variety of matchers the help make life easy.

  • assertThatInt – typed assert that expects an int (other types too: assertThatFloat, assertThatDouble, etc.)
  • equalToInt – typed equals that takes an int (other types too: equalToFloat, equalToDouble, equalToBool, etc.)
  • closeTo – match a number with a target number plus or minus a delta (both params are double)
  • lessThan – match a number less than the given number (param is NSNumber), also lessThanOrEqualTo
  • greaterThan – match a number greater than the given number (param is NSNumber), also greaterThanOrEqualTo
assertThatInt(5, equalToInt(5));
assertThatFloat(3.14, equalToFloat(3.14f));
assertThatBool( false, equalToBool(NO) );
 
NSNumber *i = [NSNumber numberWithInt:5];
assertThat(i, equalToInt(5));
assertThat(i, is([NSNumber numberWithInt:5]));
 
NSNumber *f = [NSNumber numberWithFloat:3.14f];
assertThat(f, equalToFloat(3.14f));
assertThat(f, is([NSNumber numberWithFloat:3.14f]));

The easiest cleanest approach is to use assertThatInt with equalToInt, the next best option is to use the vanilla assertThat with equalToInt, the most verbose option is to use NSNumber everywhere.

It’s easy to make rough number comparisons too:

NSNumber *f = [NSNumber numberWithFloat:3.14f];
assertThat(f, closeTo(3.0f, 0.25f));
 
assertThat(f, lessThan([NSNumber numberWithInt:4]));
assertThat(f, greaterThan([NSNumber numberWithInt:3]));

NOTE: It is a little weird, but closeTo takes double params, but everything else expects NSNumber params.

Numeric comparisons also work great on dates too:

NSDate *now = [NSDate date];
 
//now minus 1000 seconds
NSDate *beforeNow = [NSDate dateWithTimeIntervalSinceNow:-1000]; 
 
assertThat(now, greaterThan(beforeNow));

Matching Arrays

Easily the best part of OCHamcrest is its ability to match lists of objects. Array matchers are every powerful, but don’t forget to add the terminating nil to all lists.

  • hasItem – match if given item appears in the list
  • hasItems – match if all given items appear in the list (in any order)
  • contains – match exactly the entire array
  • containsInAnyOrder – match entire array, but in any order
  • hasCountOf – match the size of the array
  • empty – match an empty array

Here some basic array examples:

NSArray *a = [NSArray array];
 
assertThat(a, is(empty()));
assertThat(a, hasCountOf(0));

Here some hasItem examples:

NSArray *a = [NSArray arrayWithObjects:@"a", @"b", @"c", nil];
 
assertThat(a, hasItem(@"a"));
assertThat(a, isNot(hasItem(@"X")));
assertThat(a, hasItem(equalToIgnoringCase(@"A")));

The last matcher may look a little weird, but remember matchers expect a matcher as their input param, and only default to equalTo if none is given. Thus, the first matcher hasItem(@"a") can be rewritten as hasItem(equalTo(@"a")).

We repeat the above example, but this time using numbers in our NSArray. As you can see below, all the number matchers require us to explicitly use equalToInt everywhere:

NSArray *a = [NSArray arrayWithObjects:
    [NSNumber numberWithInt:2],
    [NSNumber numberWithInt:3],
    [NSNumber numberWithInt:5],
    nil];
 
assertThat(a, hasItem(equalToInt(2)));
assertThat(a, isNot(hasItem(equalToInt(13))));
 
assertThat(a, contains(equalToInt(2), equalToInt(3), equalToInt(5), nil));

Here are some more complex array matchers:

NSArray *a = [NSArray arrayWithObjects:@"a", @"b", @"c", nil];
 
assertThat(a, hasItems(@"b", @"a", nil));
 
assertThat(a, contains(@"a", @"b", @"c", nil));
assertThat(a, containsInAnyOrder(@"c", @"b", @"a", nil));
 
assertThat([a componentsJoinedByString:@","], is(@"a,b,c"));

And as I show in the last matcher, you can always dump to a string, and just match strings.

Matching Dictionaries

The dictionary matchers build on the array matchers:

  • hasKey – match a key
  • hasValue – match a value
  • hasEntry – match a key-value pair
  • hasEntries – match a list of k-v pairs
NSDictionary *d = [NSDictionary dictionaryWithObjectsAndKeys:
    @"valA", @"keyA", @"valB", @"keyB", @"valC", @"keyC", nil];
 
assertThat(d, hasCountOf(3));
assertThat(d, isNot(empty()));
 
assertThat(d, hasKey(@"keyA"));
assertThat(d, isNot(hasKey(@"keyX")));
 
assertThat(d, hasValue(@"valA"));
 
assertThat(d, hasEntry(@"keyA", @"valA"));
 
assertThat(d, hasEntries(@"keyA", @"valA", @"keyC", @"valC", nil));

Matcher Error Messages

When a matcher fails, you get a standardize error message of: Expected "foo", but was "bar". This default message is easy to modify by using the describedAs() matcher in place of the typical is() matcher.

NSString *s = @"bar";
 
assertThat(s, is(@"foo"));
//Expected "foo", but was "bar"
 
assertThat(s, describedAs(@"doh! this should be 'foo'", equalTo(@"foo"), nil));
//Expected doh! this should be 'foo', but was "bar"
 
assertThat(s, describedAs(@"doh! this should be foo, %0, %1", equalTo(@"foo"), @"baz", [NSNumber numberWithInt:42], nil));
//Expected doh! this should be foo, "baz", <42>, but was "bar"

NOTE: The argument list for describedAs() MUST end with nil or your tests will crash instantly with no useful error message.

Building a Custom Matcher

Writing your own custom matchers is relatively easy. Here’s an example of a matcher that matches the value of some property on an object:

#import <OCHamcrestIOS/OCHamcrestIOS.h>
#import <objc/objc-api.h>
 
@interface HasProperty : HCBaseMatcher {
    NSString *property;
    id<HCMatcher> valueMatcher;
}
 
+ (id) hasProperty:(NSString *)aProperty value:(id<HCMatcher>)aValueMatcher;
- (id) initWithProperty:(NSString *)aProperty value:(id<HCMatcher>)aValueMatcher;
 
@end
 
OBJC_EXPORT id<HCMatcher> hasProperty(NSString *property, id valueMatcher);

We extends HCBaseMatcher with our custom HasProperty class. We store the name of the property and a value matcher.

And the implementation:

#import "HasProperty.h"
#import <OCHamcrestIOS/HCDescription.h>
#import <OCHamcrestIOS/HCWrapInMatcher.h>
 
@implementation HasProperty
 
+ (id) hasProperty:(NSString *)aProperty value:(id<HCMatcher>)aValueMatcher {
    return [[[self alloc] initWithProperty:aProperty value:aValueMatcher] autorelease];
}
 
- (id) initWithProperty:(NSString *)aProperty value:(id<HCMatcher>)aValueMatcher {
    self = [super init];
    if (self != nil) {
        property = [aProperty copy];
        valueMatcher = [aValueMatcher retain];
    }
    return self;
}
 
- (void) dealloc {
    [property release];
    [valueMatcher release];
    [super dealloc];
}
 
- (BOOL)matches:(id)item {
    SEL propertyGetter = NSSelectorFromString(property);
 
    if ([item respondsToSelector:propertyGetter]) {
        if ([valueMatcher matches:[item performSelector:propertyGetter]])
            return YES;
    }
    return NO;
}
 
- (void) describeTo:(id<HCDescription>)description {
    [[[description appendText:[NSString stringWithFormat:@"an object with a property named '%@' with a value of {", property]]
        appendDescriptionOf:valueMatcher]
        appendText:@"}"];
}
@end
 
OBJC_EXPORT id<HCMatcher> hasProperty(NSString *property, id valueMatcher) {
    return [HasProperty hasProperty:property value:HCWrapInMatcher(valueMatcher)];
}

When we write a custom matcher, we must implement two methods, matches: to do the matching and describeTo: to provide feedback in case of match failure. In the above code, we first construct a selector from the given property name, then call the selector to get the actual property value, and finally check if actual matches the expected value (given by the valueMatcher).

Usage looks like this:

Person *p = [Person personWithFirstName:@"Joe" andLastname:@"Doe"];
 
assertThat(p, hasProperty(@"firstName", @"Joe"));

Or more importantly, we can now use our custom hasProperty matcher to match an arrays of objects:

NSArray *a = [NSArray arrayWithObjects:
    [Person personWithFirstName:@"Joe" andLastname:@"Doe"],
    [Person personWithFirstName:@"Joe" andLastname:@"Smith"],
    [Person personWithFirstName:@"Jane" andLastname:@"Allen"],
    nil];
 
assertThat(a, contains(
    hasProperty(@"firstName", @"Joe"),
    hasProperty(@"firstName", @"Joe"),
    hasProperty(@"firstName", @"Jane"),
    nil));

That’s it. Go forth and match.

UPDATE: I put the above hasProperty matcher into a pull request, and Jon Reid accepted it into OCHamcrest v1.6. He even wrote a nice post about it. Get the lastest OCHamcrest from github.

Links


 3.21

Over the past three years, I’ve been programming mostly Flex and Java, with few other languages sprinkled on top (Javascript, PHP, Erlang). Recently, I’ve made the transition to doing exclusively iOS development and slinging Objective-C all day long (I’ve even taken over the Boulder iOS meetup). Here’s my take on Objective-C as a programming language, along with a snapshot of life from the trenches of a professional Objective-C developer.

The Good

Using square brackets to call methods is a little wack, but you’ll get over that in about 20 minutes. Honestly, the syntax is a little bumpy for a day or two, tops…after that, there’s a lot to like about Objective-C.

Dynamic

Objective-C is a very dynamic language, not quite at the level of Ruby, but it’s pretty dang close. You’ve got the id data type when you need dynamic typing, but you can also use static typing for some compiler love. You’ve got Categories for extending classes. And you’ve got full-on runtime meta-programming that allows you to create new classes at runtime, create new methods on existing classes at runtime, and swizzle methods at runtime. Objective-C’s also got message forwarding (just a more verbose method_missing if you know Ruby) for handling unknown method calls at runtime.

Not to shabby. With the exception of the id data type and using @selector everywhere, I seldom use the dynamic features. Since dynamism is completely unobtrusive in Objective-C, I don’t have to worry about it, but I know it’s there if I need it. Basically, it’s a big warm fuzzy.

Blocks

Closures are pretty sweet in any language, but the Objective-C implementation, called Blocks, is better than most. The addition of Blocks means that functions are now first class objects in the runtime, meaning they can be created, saved, executed, copied, or passed to other functions at runtime. Blocks are directly supported by the base Objective-C classes and in some iOS APIs too (examples include NSArray‘s enumerateObjectsUsingBlock: or UIView‘s animateWithDuration:animations:).

But the coolest thing you can do with Blocks is to use them to create chucks of work that can be executed in parallel. The hard part is breaking a job out into independent chunks of work, but once you have that implementation is trivial in Objective-C. You just use NSArray‘s enumerateObjectsWithOptions:usingBlock: with the NSEnumerationConcurrent option to do work on the chunks concurrently, like this:

[myArray enumerateObjectsWithOptions:NSEnumerationConcurrent
                          usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    //do chunk of work on obj
}];

And if you really need to some concurrent kung-fu, Objective-C provides NSOperationQueue along with Grand Central Dispatch to really kick some ass. If you can forgive the Charlie Sheen reference, I like to think of Blocks as the tiger blood of concurrent programming. Winners use Blocks.

Good references: Drew McCormack’s 10 Uses for Blocks; Make Ash’s part 1 and part 2; Mike Clark’s basic blocks and advanced blocks.

UIAutomation

UIAutomation is not much to look at. And it actually starts looking pretty bad as a functional testing tool when compared to Selenium or FlexMonkey or FoneMonkey. But it’s there, it works, it’s full-baked, and it appears to be Apple’s way forward. Automation is so powerful, particularly on big apps developed by big teams. UIAutomation’s integration with Instruments is it’s achilles heel right now, so hopefully Apple brings out an update that is happily command-line-runnable soon. Until then, it’s still super awesome to have an automation tool.

The Bad

There’s a lot of not-good-yet stuff in Objective-C development. For the most part, I’m optimistic that much of stuff will get fixed over time.

The Community

With the exception of Stack Overflow (and that’s a major exception because it’s just awesome), the Objective-C community is just getting started, for the obvious reason that it’s so new on the radar. The number of books, bloggers, libraries, frameworks, et cetera is just not there yet. From my own personal experience, I find it very analogous to the Ruby community circa Rails 1.0. A few, well known, super dev bloggers, a few good books, a few widely used frameworks (Three20, cocos2d), and a lot of eager wannabes (like me then with ruby, and me now with iOS) [Note to self: Am I just a career wannabe? Discuss.] But look at ruby now…the community got so big that they are now experiencing contraction (the Rails/Merb merge is the big example).

I’m always googling while writing code, but with Objective-C I often find myself coming up empty. A lot of first time never-been-done-before stuff is going on in Objective-C and iOS, which is certainly exciting, but not without its challenges to day-to-day development. I don’t doubt things will improve in the future, but right now I find the community lacking.

Tools

Much like the community, the tool chain is just getting started. There’s a ton of Makefiles out there, along with piles of bash scripts. And I swear people are still jumping to the command line in gdb. Of course, this is all the C/C++ heritage, but come on people! Who uses this stuff and actually likes it? It’s not like Ant and Maven were forged by the gods, but Makefiles? Save me.

And what’s up with Other Linker Flags? This whole thing to totally idiotic. Why can’t we invent some new packaging format that knows it must be added with -lstdc++ or -ObjC? Super lame.

I’ve been getting pretty dirty with Rake, Ivy, and Sonatype’s Nexus to bring some serenity to the situation. Definitely a work in progress, but it’s getting there.

The Ugly

The ugly parts are rather unfortunate, especially given the beauty of Apple’s hardware. It’s also a little hard for non-programmers to see, because the user-facing bits of the software can be made so beautiful too. But I would certainly argue that the beauty of the UI is done despite of some evil ugly warts in the code. Maybe I’m being a little too Zen, or maybe I’m a hopeless romantic, or maybe I’m just being naive, but it sure would be great if inner beauty at the code level eventually lead to beauty at the surface.

Memory Management

Everyone loves to hate on Objective-C’s lack of garbage collection on iOS. I’m on the bandwagon on this one too, because memory management just plain sucks. The constant dance of retain, release, and autorelease is unrelenting, and so hateful! For an alternate data point, with the release of Gingerbread, Android has a new concurrent garbage collector. Come on Apple, give us some love.

Writing leak free code on the first pass is basically impossible, especially on a big app. So now I’ve had to expand my toolbox to include tools like Clang and Leaks and UIAutomation to find and fix all my memory bugs. It’s just ugly plain and simple.

Xcode

By far the ugliest part of Objective-C is the Xcode IDE. By far! I’ve used the question, "Tell me about some of the warts of iOS development?", a couple of times in recent interviews. It turns out to be a great differentiator between professional developers that are familiar with team development and professional tools and people that know how to code. All the candidates I’ve asked can easily point to memory management as one of the ugly parts, but almost no one says the Xcode.

If you’ve ever used a real IDE (Eclipse, IntelliJ, Visual Studio), then you are probably familiar with various code-level helpers like generate getters/setters, rename class, automatic code formatting on save, just to give a few examples. Xcode doesn’t generate getters or setters from ivars. Nor does it do class rename, only file rename, how pathetic is that? It doesn’t do any intelligent code formatting either on save or otherwise. And these are just my code-level gripes…

You are also probably familiar with the various development tooling integrations that put the I in Integrated Development Environment. Things like using source control, viewing graphical diffs, running unit tests, running scripts, debugging with variable watches, writing tickets, submitting bug reports, doing code reviews, and more. Nope, Xcode doesn’t do any of those things either.

In the end, I give Xcode a "syntax highlighter plus" rating, which puts it just above vanilla Vim but below a super tricked out Vim setup.

Conclusion

I’m an iOS developer by choice, but just because I’m splashing around in the mud like a happy pig right now doesn’t mean I like being dirty all the time. [For more about "the mud", read my rablings here.] The ugly bits do have one positive effect: my value (and hence my salary) are improved. By setting the bar high, either intentionally or unintentionally, Apple is effectively keeping the riffraff out.

Hopefully, GC will arrive once all the iOS hardware gets multiple cores. Or maybe ARC might be decent. And JetBrains CIDR (Objective-C IDE from the makers of IntelliJ) will turn out to be awesome. Onward and upward.

Update 2013-04-17: Yes, ARC is pretty sweet. Yes, JetBrains AppCode is the real deal. And yes, Xcode is still an ugly wart on iOS development.


 3.8

I always believe in the right tool for the job, so I’m not an Interface Builder hater per se, but I find it a little pathetic how infrequently IB is the right tool for the job. In addition, I’ve found IB to be at its worst whenever the development team is bigger than one. Don’t panic, just go nibless.

It’s very easy to go completely nibless (and a little stylish in my opinion) and eschew Interface Builder altogether. For all you Flexers out there, this is the moral equivalent of eschewing Flash Builder’s Design View. Honestly, who really uses Design View to build an app beside Adobe evangelists doing 30 minute demos?

A Completely Nibless App

Here’s how you can build a completely nibless app in five simple steps. First, you’ll want to start with a fresh Window-based Application in Xcode. Then follow these steps:

  1. Remove MainWindow from your app’s Info.plist
  2. Delete all .xib files
  3. Edit AppDelegate.h remove all the IBOutlet keywords
  4. Edit main.m, import AppDelegate.h, and set the UIApplicationMain‘s 4th parameter to @"AppDelegate"
  5. Edit AppDelegate.m to instantiate the main UIWindow in code

Here’s what main.m should look like after you’ve completed Step 4:

#import <UIKit/UIKit.h>
#import "AppDelegate.h"
 
int main(int argc, char *argv[]) {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    int retVal = UIApplicationMain(argc, argv, nil, @"AppDelegate");
    [pool release];
    return retVal;
}

And here’s what the application:didFinishLaunchingWithOptions: method in AppDelegate.m should look like:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
    [self.window makeKeyAndVisible];
    return YES;
}

Now you can go about you view-creation business in a nibless fashion. I’d probably create a UIViewController subclass as my root view, construct my UI in loadView, and wire everything together in the AppDelegate.

Nibless App Xcode Template

But don’t do any of that stuff! Instead you can just use this handy-dandy Xcode template to do all the work. On of the very few things Xcode gets right is its template system. It is very easy to create a custom template for Xcode (see here and here for the basics).

Install the NiblessApp custom template in Xcode:

  1. Download nibless_app_template.tgz
  2. cd ~/Library/Application Support/Developer/Shared/Xcode/Project Templates/ (you might need to create the Project Templates folder if it doesn’t already exist)
  3. tar xzvf /path/to/nibless_app_template.tgz
  4. Quit Xcode and restart
Files

 2.21

This is all out there on the web, but I’m putting everything here all in one place so as not to forget. Just a simple Stack and Queue implementation as a category on NSMutableArray. It works and it doesn’t suck, and that’s all I’ll say about it.

Stack

A very basic Stack implementation with just push, pop, and peek.

@interface NSMutableArray (Stack)
 
- (void) push: (id)item;
- (id) pop;
- (id) peek;
 
@end
@implementation NSMutableArray (Stack)
 
- (void) push: (id)item {
    [self addObject:item];
}
 
- (id) pop {
    id item = nil;
    if ([self count] != 0) {
        item = [[[self lastObject] retain] autorelease];
        [self removeLastObject];
    }
    return item;
}
 
- (id) peek {
    id item = nil;
    if ([self count] != 0) {
        item = [[[self lastObject] retain] autorelease];
    }
    return item;
}
 
@end

No real magic above, just Objective-C’s annoying retain & autorelease dance to get an item out of NSMutableArray correctly.

Queue

Much like Stack above, here’s a very basic Queue implementation with just enqueue, dequeue, and peek.

@interface NSMutableArray (Queue)
 
- (void) enqueue: (id)item;
- (id) dequeue;
- (id) peek;
 
@end
@implementation NSMutableArray (Queue)
 
- (void) enqueue: (id)item {
    [self addObject:item];
}
 
- (id) dequeue {
    id item = nil;
    if ([self count] != 0) {
        item = [[[self objectAtIndex:0] retain] autorelease];
        [self removeObjectAtIndex:0];
    }
    return item;
}
 
- (id) peek {
    id item = nil;
    if ([self count] != 0) {
        item = [[[self objectAtIndex:0] retain] autorelease];
    }
    return item;
}
 
@end

Note that we need the same retain & autorelease dance as above.

Files

© 2014 saturnboy.com