Programmer Values

A question and answer exchange over at programmers.stackexchange.com reveals something interesting about how software is valued. The question asked whether there is any real-world data regarding costs and benefits of test-driven development.[*] One of the answers contained, at time of writing, the anthropologist’s money shot:

The first thing that needs to be stated is that TDD does not necessarily increase the quality of the software (from the user’s point of view). […] TDD is done primarily because it results in better code. More specifically, TDD results in code that is easier to change. [Emphasis original]

Programmers are contracted, via whatever means, by people who see quality in one way: presumably that quality is embodied in software that they can use to do some thing that they wanted to do. Maybe it’s safer to say that the person who provided this answer believes that their customers value quality in software in that way, rather than make an assumption on everybody’s behalf.

This answer demonstrates that (the author believed, and thought it uncontentious enough to post without defence in a popularity-driven forum) programmers value attributes of the code that are orthogonal to the values of the people who pay them. One could imagine programmers making changes to some software that either have no effect or even a negative effect as far as their customers are concerned, because the changes have a positive effect in the minds of the programmers. This issue is also mentioned in one of the other answers to the question:

The problem with developers is they tend to implement even things that are not required to make the software as generic as possible.

The obvious conclusion is that the quality of software is normative. There is no objectively good or bad software, and you cannot discuss quality independent of the value system that you bring to the evaluation.

The less-obvious conclusion is that some form of reconciliation is still necessary: that management has not become redundant despite the discussions of self-organised teams in the Agile development community. Someone needs to mediate between the desire of the people who need the software to get something that satisfies their norms regarding quality software, and the desire of the people who make the software to produce something that satisfies their norms instead. Whether this is by aligning the two value systems, by ignoring one of them or by ensuring that the project enables attributes from both value systems to be satisfied is left as an exercise for the reader.

[*] There is at least one relevant study. No, you might not think it relevant to your work: that’s fine.

Lighter UIViewControllers

The first issue of Objective-C periodical objc.io has just been announced:

Issue #1 is about lighter view controllers. The introduction tells you a bit more about this issue and us. First, Chris writes about lighter view controllers. Florian expands on this topic with clean table view code. Then Daniel explores view controller testing. Finally, in our first guest article, Ricki explains view controller containment.

Each of the articles is of a high quality, I thoroughly recommend that you read this. I powered through it this morning and have already put myself on the mailing list for the next issue. I think it’s worth quite a few dollars more than the $0 they’re asking.

On a more self-focussed note, I’m pleased to note that two of the articles cite my work. This isn’t out of some arrogant pleasure at seeing my name on someone else’s website. One of my personal goals has been to teach the people who teach the other people: to ensure that what I learn becomes a part of the memeplex and isn’t forgotten and reinvented a few years later. In APPropriate Behaviour a few of the chapters discuss the learning and teaching of software making. I consider it one of the great responsibilities of our discipline, to ensure the mistakes we had to make are not made by those who come after us.

The obj.io team have done a great job of researching their articles, taking the knowledge that has been found and stories that have been told and synthesising new knowledge and new stories from them. I’m both proud and humble about my small, indirect role in this effort.

Specifications for interchanging objects

One of the interesting aspects of Smalltalk and similar languages including Objective-C and Ruby is that while the object model exposes a hierarchy of classes, consumers of objects in these environments are free to ignore the position of the object in that hierarchy. The hierarchy can be thought of as a convenience: on the one hand, for people building objects (“this object does all the same stuff as instances of its parent class, and then some”). It’s also a convenience for people consuming objects (“you can treat this object like it’s one of these types further up the hierarchy”).

So you might think that -isKindOfClass: represents a test for “I can use this object like I would use one of these objects”. There are two problems with this, which are both expressed across two dimensions. As with any boolean test, the problems are false positives and false negatives.

A false positive is when an object passes the test, but actually can’t be treated as an instance of the parent type. In a lot of recent object-oriented code this is a rare problem. The idea of the Liskov Substitution Principle, if not its precise intent as originally stated, has become entrenched in the Object-Oriented groupthink.

I’ve worked with code from the 1980s though where these false positives exist: an obvious example is “closing off” particular selectors. A parent class defines some interface, then subclasses inherit from that class, overriding selectors to call [self doesNotRecognize:] on features of the parent that aren’t relevant in the subclass. This is still possible today, though done infrequently.

False negatives occur when an object fails the -isKindOfClass: test but actually could be used in the way your software intends. In Objective-C (though neither in Smalltalk[*] nor Ruby), nil _does_ satisfy client code’s needs in a lot of cases but never passes the hierarchy test. Similarly, you could easily arrange for an object to respond to all the same selectors as another object, and to have the same dynamic behaviour, but to be in an unrelated position in the hierarchy. You _can_ use an OFArray like you can use an NSArray, but it isn’t a kind of NSArray.

[*] There is an implementation of an Objective-C style Null object for Squeak.

Obviously if the test is broken, we should change the test. False negatives can be addressed by testing for protocols (again, in the languages I’ve listed, this only applies to Objective-C and MacRuby). Protocols are unfortunately named in this instance: they basically say “this object responds to any selector in this list”. We could then say that rather than testing for an object being a kind of UIView, we need an object that conforms to the UIDrawing protocol. This protocol doesn’t exist, but we could say that.

Problems exist here. An object that responds to all of the selectors doesn’t necessarily conform to the protocol, so we still have false negatives. The developer of the class might have forgotten to declare the protocol (though not in MacRuby, where protocol tests are evaluated dynamically), or the object could forward unknown selectors to another object which does conform to the protocol.

There’s still a false positive issue too: ironically protocol conformance only tells us what selectors exist, not the protocol in which they should be used. Learning an interface from a protocol is like learning a language from a dictionary, in that you’ve been told what words exist but not what order they should be used in or which ones it’s polite to use in what circumstances.

Consider the table view data source. Its job is to tell the table view how many sections there are, how many rows there are in each section, and what cell to display for each row. An object that conforms to the data source protocol does not necessarily do that. An object that tells the table there are three sections but crashes if you ask how many rows are in any section beyond the first conforms to the protocol, but doesn’t have the correct dynamic behaviour.

We have tools for verifying the dynamic behaviour of objects. In his 1996 book Superdistribution: Objects as Property on the Electronic Frontier, Brad Cox describes a black box test of an object’s dynamic behaviour, in which test code messages the object then asserts that the object responds in expected ways. This form of test was first implemented in a standard fashion, to my knowledge, in 1998 by Kent Beck as a unit test.

Unit tests are now also a standard part of the developer groupthink, including tests as specification under the name Test-Driven Development But we still use them in a craft way, as a bespoke specification for our one-of-a-kind classes. What we should really do is to make more use of these tests: substituting our static, error-prone type tests for dynamic specification tests.

A table view does not need something that responds to the data source selectors, it needs something that behaves like a data source. So let’s create some tests that any data source should satisfy, and bundle them up as a specification that can be tested at runtime. Notice that these aren’t quite unit tests in that we’re not testing our data source, we’re testing any data source. We could define some new API to test for satisfactory behaviour:

- (void)setDataSource: (id <UITableViewDataSource>)dataSource {
  NSAssert([Demonstrate that: dataSource satisfies: [Specification for: @protocol(UITableViewDataSource)]]);
  _dataSource = dataSource;
  [self reloadData];
}

But perhaps with new language and framework support, it could look like this:

- (void)setDataSource: (id @<UITableViewDataSource>)dataSource {
  NSAssert([dataSource satisfiesSpecification: @specification(UITableViewDataSource)]);
  _dataSource = dataSource;
  [self reloadData];
}

You could imagine that in languages that support design-by-contract, such as Eiffel, the specification of a collaborator could be part of the contract of a class.

In each case, the expression inside the assertion handler would find and run the test specification appropriate for the collaborating object. Yes this is slower than doing the error-prone type hierarchy or conformance tests. No, that’s not a problem: we want to make it right before making it fast.

Treating test fixtures as specifications for collaboration between objects, rather than (or in addition to) one-off tests for one-off classes, opens up new routes for collaboration between the developers of the objects. Framework vendors can supply specifications as enhanced documentation. Framework consumers can supply specifications of how they’re using the frameworks as bug reports or support questions: vendors can add those specifications to a regression testing arsenal. Application authors can create specifications to send to contractors or vendors as acceptance tests. Vendors could demonstrate that their code is “a drop-in replacement” for some other code by demonstrating that both pass the same specification.

But finally it frees object-oriented software from the tyranny of the hierarchy. The promise of duck typing has always been tempered by the dangers, because we haven’t been able to show that our duck typed objects actually can quack like ducks until it’s too late.

BrowseOverflow as a Code Kata

This article was originally posted over at InformIT.

My goal in writing Test-Driven iOS Development was to take readers from not knowing how to write a test for their iOS apps, to understanding the TDD workflow and how it could work for them. That mirrored the journey that I had taken in learning about test-driven development, and that had led me to wanting to write a book to share what I’d learned with my peers.

This has an interesting effect on the structure of the book. Not all of the sample code from the BrowseOverflow is shown (though it’s all available on GitHub). This isn’t an accident we made in the editorial process. It’s a feature: for any test shown in the book, there are numerous different ways you could write application code that would all be just as good. Anything that causes the test to pass, and doesn’t make the other tests fail, is fine.

Just as the many-worlds model in quantum theory says that there are many branches of the universe that are created every time a decision is made, so there’s a “many-BrowseOverflows” model of Test-Driven iOS Development. Every time a test is written, there are many different solutions to passing the test, leading to there being multiple potential BrowseOverflows. The code that you see on GitHub is just one possible BrowseOverflow, but any other code that satisfies the same tests is one of the other possible BrowseOverflows.

This means that you can treat the book like a kata: the Japanese martial art technique of improving a practice by repeating it over and over. The first time you read Test-Driven iOS Development, you can choose to follow the example code very closely. Where the code isn’t given in the book, you might choose to look at the source code to understand how I solved the problems posed by the tests. But the end of the book is not the end of the journey: you can go back, taking the tests but implementing all of the app code yourself. You can do this as many times as you want, trying to find new ways to write code that produces a BrowseOverflow app.

Finally, when you’re more confident with the red-green-refactor way of working, you can write a BrowseOverflow app that’s entirely your own creation. You can define what the app should do, create tests that express those requirements and write the code to implement it however you like. This is a great way to test out new ways of working, for example different test frameworks like GHUnit or CATCH. It also lets you try out different ways of writing the application code: you could write the same app but trying to use more blocks, or try to use the smallest number of properties in any class, or any other challenge you want to set yourself. Because you know what the software should be capable of, you’re free to focus on whatever skill you’re trying to exercise.

Building a unit test target with GNUstep make

Just a quick note on how I build my test tools (they run separately, either by manual invocation or via CI) when I’m working in GNUstep.

Firstly, you’ll need Catch. Then given test files that look like this:

test_class.mm
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#import 

TEST_CASE("Using foundation", "I should be able to use Foundation classes from a test tool")
{
  NSArray *array = [NSArray array];
  REQUIRE([array count] == 0);
}

(only one of your files should define CATCH_CONFIG_MAIN as you must only have one main function).

Then I define a tests target in my Makefile:

GNUmakefile

include $(GNUSTEP_MAKEFILES)/common.make

#… stuff to define my app target

TEST_TOOL_NAME=tests
tests_OBJCC_FILES = test_class.mm other_tests.mm blah.mm
tests_OBJCCFLAGS="-ICatch/include"

-include Makefile.preamble

#… include target definitions for the app target
include $(GNUSTEP_MAKEFILES)/test-tool.make

-include Makefile.postamble

And there it is. Now whenever I make my app I also get obj/tests which’ll run the test suite for me.

Metacognition-driven development

To find out what techniques work for you in a field of practice, you often need to think about how you think. To decide what it is that drives your learning processes, and then adapt your practices to suit that.

For example, I tend to get more done if I’m already getting something done. Success breeds success. If I don’t feel like I’m succeeding, then I’ll break off and do something else (like write a blog post in my lunch break). I don’t think that’s unique to me, though, as common phrases like “on a roll” and “in the zone” seem to imply being in a state where progress begets more progress.

Cognition scientists know this, too. The authors of Yes! describe an experiment in which they tried two types of card in a hotel to get guests to reuse their towel instead of having them laundered every day. One contained the message that if a guest reused her towel, the hotel would make a donation to an environmental charity on her behalf. The other said that the hotel had already made the donation, and all the guest had to do to complete the story was to reuse her towel.

The second card was more effective. It implies that progress has already been made: that the guest has already succeeded (albeit vicariously) in making a donation. Success begets success, so the guests are more likely to make continued progress: i.e. to reuse the towels.

That is, I think, why TDD makes me work faster than when I’m not doing TDD. Because I can see the green lights, because I can see the little nuggets of success that will go together to make the feature work. It turns “I still haven’t posted the message to the server” into “woo! I just configured the URL request”. It turns “still losing” into “yet another win”. It doesn’t trick me into thinking I’m making more progress, but it does let me see that progress is being made.

Classes are globals, too

Software engineers are used to the notion that global variables are a bad idea. Globals are usually accessed by asking, not by telling. They introduce tight coupling between any module that uses the global and the one that declares it, and (more dangerously) implicit coupling between all of the modules that use the global.

It can be hard to test code that uses globals. You typically need to supply a different object (by which I mean a linker object) that exports the same symbol, so that in tests you get to configure the global as you need it. Good luck if that’s deeply embedded in other code you do need, like NSApp.

While we’re on the subject of global variables, the names of classes are all in the global namespace. We know that: there is only one NSKeyedUnarchiver class, and everyone who uses the NSKeyedUnarchiver class gets the same behaviour. If any module that uses NSKeyedUnarchiver changes it (e.g. by swizzling a method on the metaclass), then every other client of NSKeyedUnarchiver gets the modified behaviour.

[If you want a different way of looking at this: Singletons are evil, and each class is the singleton instance of its metaclass, therefore class objects are evil.]

Now that makes it hard to test use of a class method: if I want to investigate how my code under test interacts with a class method, I have these options:

  • Swizzle the method. This is possible, but comparatively high effort and potentially complicated; should the swizzled method call through to the original or reimplement parts of it behaviour? What goes wrong if it doesn’t, and what needs to be supported if it does? Using the example of NSKeyedArchiver, if you needed to swizzle +archiveRootObject:toFile: you might need to ensure that the object graph still receives its -encodeWithCoder: messages – but then you might need to make sure that they send the correct data to the coder…
  • Tell the code under test what class to use, don’t let it ask. So you’d have a property on your object @property (nonatomic, strong) Class coderClass; and then you’d use the +[coderClass archiveRootObject:toFile:] method. In your app, you set the property to NSKeyedArchiver and in the tests, to whatever it is you need.

    That’s simple, and solves the problem, but rarely seen. I think this is mainly because there’s no way to tell the Objective-C compiler “this variable represents a Class that’s NSCoder or one of its subclasses”, so it’s hard to convince the type-safety mechanism that you know archiverClass responds to +archiveRootObject:toFile:.

  • Use instance methods instead of class methods, and tell the code you’re testing what instance to use. This is very similar to the above solution, but means that you pass a fully-configured object into the code under test rather than a generic(-ish) class reference. In your code you’d have a property @property (nonatomic, strong) NSCoder *coder in to -encodeRootObject: and rely on it having been configured correctly to know what to do as a result of that.

    This solution doesn’t suffer from the type-safety problem introduced in the previous solution; you told the compiler that you’re talking to an NSCoder (but not what specific type of NSCoder) so it knows you can do -encodeRootObject:.

Notice that even if you decide to go for the third solution here (the one I usually try to use) and use object instances instead of classes for all work, there’s one place where you must rely on a Class object: that’s to create instances of the class. Whether through “standard” messages like +alloc or +new, or conveniences like +arrayWithObjects:, you need a Class to create any other Objective-C object.

I’d like to turn the above observation into a guideline to reduce the proliferation of Class globals: an object’s class should only be used at the point of instantiation. Once you’ve made an object, pass it to the object that needs it, which should accept the most generic type available that declares the things that object needs. The generic type could be an abstract class like NSCoder or NSArray (notice that all array objects are created by the Foundation library, and application code never sees the specific class that was instantiated), or a protocol like UITableViewDataSource.

Now we’ve localised that pesky global variable to the smallest possible realm, where it can do the least damage.

TDD and crypto in one place

Well, I suppose if I’ve written two books, it’s about time I wrote a contorted blog post that references both of the worlds.

I recently wrote an encryption module for an app, and thought it’d be useful to share something about the design process. Notice that the source code here was quickly thrown together for the purposes of demonstrating the design technique, and bears little resemblance to the code I was actually writing (which was in a different language). A lot of the complexity I was actually trying to deal with has been elided in order to bring the story to the fore.

Steps 1a, 2a, 1b, 2b etc: Design the API hand-in-hand with a fake implementation.

A pass-thru implementation would work here, but I prefer to use something that actually does change its input just so that it’s clear that there’s a requirement the input should be acted on. You might end up with tests that look something like this:

@implementation CryptoDesignTests
{
    id <StringEncryptor>cryptor;
}

- (void)setUp {
    cryptor = [[ROT13StringEncryptor alloc] init];
}

- (void)tearDown {
    cryptor = nil;
}

- (void)testEncryptionOfPlainText {
    NSString *plainText = @"hello";
    NSString *cipherText = [cryptor encipherString: plainText];
    STAssertEqualObjects(@"uryyb", cipherText, @"This method should encrypt its parameter");
}

- (void)testDecryptionOfCipherText {
    NSString *cipherText = @"uryyb";
    NSString *plainText = [cryptor decipherString: cipherText];
    STAssertEqualObjects(@"hello", plainText, @"This method should decrypt its parameter");
}

@end

Where the protocol looks like this:

@protocol StringEncryptor <NSObject>

- (NSString *)encipherString: (NSString *)plainText;
- (NSString *)decipherString: (NSString *)cipherText;

@end

Of course you can implement this however you want. Here’s one potential implementation (which may have its problems, but is only being used to guide the API design):

@interface ROT13StringEncryptor : NSObject <StringEncryptor>

@end

@implementation ROT13StringEncryptor

- (NSString *)rot13: (NSString *)original {
    NSMutableData *originalBytes = [[original dataUsingEncoding: NSASCIIStringEncoding] mutableCopy];
    for (NSInteger i = 0; i < [originalBytes length]; i++) {
        NSRange cursor = NSMakeRange(i, 1);
        char c;
        [originalBytes getBytes: &c range: cursor];
        if       (c >= 'a' && c <= 'm') c += 13;
        else if  (c >= 'n' && c <= 'z') c -= 13;
        else if  (c >= 'A' && c <= 'M') c += 13;
        else if  (c >= 'A' && c <= 'Z') c -= 13;
        [originalBytes replaceBytesInRange: cursor withBytes: &c];
    }
    return [NSString stringWithCString: [originalBytes bytes] encoding: NSASCIIStringEncoding];
}

- (NSString *)encipherString:(NSString *)plainText {
    return [self rot13: plainText];
}

- (NSString *)decipherString:(NSString *)cipherText {
    return [self rot13: cipherText];
}

@end

Step 3. Write an integration test.

Having designed the API for the class, I'd like to write an integration test that does whatever it is that the app is trying to achieve. In my real app this task was that two cryptors hooked up to each other should agree on a key and pass a message between each other. For this demo, we'll require that the cryptor can round-trip a message and end up with the original text.

@implementation CryptoRoundTripTests
{
    id <StringEncryptor>> cryptor;
}

- (void)setUp {
    cryptor = [[ROT13StringEncryptor alloc] init];
}

- (void)tearDown {
    cryptor = nil;
}

- (void)testRoundTripEncryption {
    NSString *plain = @"Mary had a little lamb.";
    NSString *outOfTheSausageMachine = [cryptor decipherString: [cryptor encipherString: plain]];
    STAssertEqualObjects(plain, outOfTheSausageMachine, @"Content should survive an encryption round-trip");
}

@end

This test passes without any extra work.

Step 4. Give that lot to the poor sap who needs to write the app.

That's right, the other developers can start working straight away. They've got the protocol which tells them what the object can do, the unit tests which explain how the API should work and the integration test that explains how you expect the object to be used.

Leaving you free to:

Step 5. Point the integration test at a different implementation of the protocol.

But you haven't written that implementation yet! It must be time to:

Step 6. Write it.

You know when it works because you have integration tests. You know it'll work with the app the other person's writing because they've got the same integration test.

So the extra artefacts that some people see as a wasteful byproduct of code-level testing — the fake implementation of the protocol for example — are demonstrably useful in this scenario. Other developers on the team can use the fake implementation as a stand-in while you're head-down coding up the production code. It's also much easier to design a class when you're not also sweating over how the internal details are going to work out, so you probably get where you're going quicker too.

Test-Driven iOS Development

Here it is, after more than a year in the making, the book that they really did want you to read! Test-driven IOS Development (Developer’s Library) (affiliate link) has finally hit the stores[*].

I wrote this book for the simple reason that it didn’t exist. Like Professional Cocoa Application Security (Wrox Professional Guides) (another affiliate link), I knew that the topic was something many people were interested in, including myself. I wanted a single place I could go to find out about using Xcode for writing unit tests, and how the Test-Driven Development approach could be applied to writing Cocoa code with Objective-C.

Well, it turned out that this place didn’t exist, so I tried my best to create it. In the book you’ll see how the BrowseOverflow app was built entirely in a test-first fashion, using OCUnit and Xcode 4. Along the way, I hope you’ll see how TDD can be useful for your own projects.

If you’re interested in finding out more about test-driven development for iOS apps, I’ll be giving a talk on the subject at iOSDev UK in Aberystwyth in July. And of course I’m happy to field questions about the book or about TDD here or over on Twitter. And of course my unit testing video training course is still available from iDeveloper.tv.

Happy testing!

[*]The availability appears to vary by country and format, so if it isn’t in your favourite (e)bookstore yet just be patient and keep refreshing that page like it’s the WWDC site.

How to TDD with CATCH

Plenty of people have asked me about the TDD framework I use. While the book Test-Driven iOS Development has code using OCUnit (for pragmatic, and previously-covered, reasons); I am currently more frequently to be discovered using Phil Nash’s CATCH framework. Here’s how you can get from New Project to first passing test. I’m starting in the same place that the book’s sample code starts: I need a Topic class that has a name.

Set up the project.

File->New Project in Xcode. Create an app project that matches your needs: an empty app will be fine. I’ll assume in this project, just as in the book, that you’ll be using Automatic Reference Counting for this project.

Now you need to add another app target. The “Empty Application” template is sufficient for this, and I call this target “Unit Tests”. When you’ve got that target set up, remove the app delegate class and the main.m file: we’ll add a test runner from CATCH.

For this target, you also have to choose whether or not to use ARC. If you enabled ARC for the app target, then the classes you’re testing will use Automatic Reference Counting, but the CATCH internals cannot because they use scary runtime hacks to dynamically generate classes from the test cases. In this walkthrough, you should enable ARC but we’ll have to edit compiler flags for a couple of files to get manual reference counting where we need it.

Check out CATCH from the GitHub project linked above. Then go into the Build Rules for your Unit Tests target, and add the path to the Catch/include source folder. For example, if you clone CATCH to the top-level folder of your Xcode project, you’ll need to add "$(SRCROOT)/Catch/include".

Locate the file Catch/projects/runners/iTchRunner/itChRunnerMain.mm (capitalisation as supplied) in Finder, and drag it onto your Xcode project. Add this file to the Unit Tests target. Now you need to go to the Build Phases inspector for your target, and under Compile Sources, next to itChRunnerMain.mm add the flag -fno-objc-arc.

Add the first test

Add a new file to the Unit Tests target, called TopicTests.mm (you don’t need the matching header file). As with itChRunnerMain.mm, you’ll need to set the -fno-objc-arc flag in the Build Phases. Include the catch.hpp header and write the test that checks for the name:

#include "catch.hpp"

TEST_CASE("Topic/Name", "Require that Topic has a name") {
    Topic *topic = [[Topic alloc] initWithName: @"iPhone"];
    REQUIRE(topic != nil);
    REQUIRE([topic.name isEqualToString: @"iPhone"]);
    [topic release];
}

Get this test to compile

So currently, the test target won’t even build: we’re using a Topic class and its name property, and these don’t exist. Add a new file to the project, an NSObject class called Topic. You could add this file to both targets as it will be app code: don’t disable ARC here because the whole point is you want to write automatically reference-counted app code.

Just to fast-forward things a bit, here’s an implementation of Topic.[hm] that contains minimal implementations of the required methods.

Topic.h
#import <Foundation/Foundation.h>

@interface Topic : NSObject

@property (readonly) NSString *name;

- (id)initWithName: (NSString *)aName;

@end

Topic.m
#import "Topic.h"

@implementation Topic

@synthesize name = _name;

- (id)initWithName:(NSString *)aName {
    if (self = [super init]) {
    }
    return self;
}

@end

Observe that the test fails.

Run the “Unit Tests” app in Xcode. You’ll see a screen like this:

Default Catch Screen

It’s not very exciting, but at least you can tell what to do: tap the “Run All Tests” button.

Catch failed test

Still not exciting, and it’s possible that if you have certain types of colour-blindness it’s not clear what’s happened. Luckily the logs are more explicit:

2012-03-13 17:18:01.640 UnitTests[960:707] Application windows are expected to have a root view controller at the end of application launch

2012-03-13 17:18:03.915 UnitTests[960:707] topic != __null succeeded for: 0x2d11b0 != __null

2012-03-13 17:18:03.917 UnitTests[960:707] [topic.name isEqualToString: @"iPhone"] failed for: false

2012-03-13 17:18:03.923 UnitTests[960:707] 1 failures

Make this test pass

There’s only one line to add to the app code to get everything passing. Here’s the Topic implementation again with the change highlighted:

@implementation Topic

@synthesize name = _name;

- (id)initWithName:(NSString *)aName {
    if (self = [super init]) {
        _name = [aName copy];
    }
    return self;
}

@end

Run the tests again:

Passing CATCH tests

2012-03-13 17:46:17.644 UnitTests[1049:707] Application windows are expected to have a root view controller at the end of application launch

2012-03-13 17:46:43.746 UnitTests[1049:707] topic != __null succeeded for: 0x2ca7f0 != __null

2012-03-13 17:46:43.748 UnitTests[1049:707] [topic.name isEqualToString: @"iPhone"] succeeded for: true

2012-03-13 17:46:43.753 UnitTests[1049:707] no failures

Win.

Conclusions

The runner for CATCH tests is currently very basic: it lets you know when things have passed or failed but not which tests have failed, though the tests are named. You need to manually prod it to get tests to run. However, the syntax is a refreshing change from the verbosity of JUnit-derived test frameworks.