Xcode: Unit Testing Cocoa frameworks

It’s straightforward to write unit tests for Objective-C Cocoa frameworks with Xcode 2.1 and later.

First, turn off ZeroLink when building your framework. ZeroLink is a great technology, but you can’t link against something that’s built with ZeroLink, and that’s exactly what your unit tests are going to do. Note: You only need to do this for Xcode 2.1 through Xcode 2.5. Xcode 3.0 removed support for ZeroLink, since the linker is now sufficiently fast as to obviate it.

Next, add a new Cocoa Unit Test Bundle target to your framework project. This is the target that will actually contain your tests.

When you add the new test bundle target Xcode should bring up its Info window. Switch to its General tab and press the + button in the lower-left to add a new dependency. In the resulting sheet, choose your framework target. This tells the build system that your framework target needs to be built before your test bundle target.

Now that you’ve declared the dependency between the targets, you need to make sure your test bundle actually links against your framework. Make your test bundle target the active target by choosing it from the Project > Set Active Target submenu. Then highlight the Products group in the Groups & Files view at the left of the Xcode project window. In the detail view to the right, you’ll see all of the products that are built by the various targets in your project; one of the rows will be for your framework. Click the checkbox at the very right of its row, in the Target Membership column, to make your test bundle link against your framework.

Now you can add test cases to your test bundle by just adding new files based on the Cocoa Objective-C test case class template. You don’t need to add any of your framework code to your test bundle, and you don’t need to add any testing code to your framework. And you’re not restricted to using only header files with public visibility in tests, either; you should be able to use anything from your framework target, so long as it’s exported at link time.

Xcode: Unit Testing

Xcode 2.1 introduced integrated unit testing to the Xcode IDE. Xcode includes two unit testing frameworks, target templates for setting up test bundle targets, and infrastructure for running unit tests every time you build your project and reporting their results in the Build Results window just like compilers and linkers do.

With Xcode unit testing, you group your test cases into test bundles which are built by separate targets. This means that you don’t need to build two versions of your software — one with tests and one without tests — and can run your tests against the actual software you want to deliver.

Xcode 2.1 and later include OCUnit for unit testing of Objective-C Cocoa software, and it includes a new framework called CPlusTest for unit testing of C++ software. Using either you should be able to test C code with relative ease. Corresponding target templates are included for creating unit test bundles appropriate for Cocoa and Carbon applications and frameworks, and file templates are included for creating OCUnit and CPlusTest test case classes.

The test bundle target templates have a shell script build phase at the very end that invokes /Developer/Tools/RunUnitTests. RunUnitTests looks at the build settings it’s passed via its environment and determines from that information how to run the tests in your test bundle.

If you’re testing a framework, RunUnitTests will run the appropriate test rig and tell it to load and run the tests in your bundle. Since your test bundle should link against your framework, your framework will be loaded when the test rig loads your bundle.

If you’re testing an application, you need to specify the application as the Test Host and Bundle Loader for your test bundle in its configuration’s build settings. The Bundle Loader setting tells the linker to link your bundle against the application that’s loading it as if the application were a framework, allowing you to refer to classes and other symbols within the application from your bundle without actually including them in the bundle. The Test Host setting tells RunUnitTests to launch the specified application and inject your test bundle into it in order to run its tests.

There’s even support in RunUnitTests for invoking a test rig of your own, rather than the test rig for one of the supplied frameworks. You just need to specify the Test Rig build setting for your test bundle; this should be the path to a tool to run. It will be passed the path to your test bundle as its first argument, and if it needs to generate failure information it can just generate it in a gcc/compiler-like format on stderr:

FailingTest.c: 10: error: (1 == 0) failed

This will cause it to show up in the Build Results window as an error, just like a compiler or linker error. You can see the RunUnitTests manpage for more information on the environment in which your test rig will be run.

There’s a great Unit Testing Guide on the Apple Developer Connection web site that has lots of information on getting started with Xcode unit testing. Check it out!

Xcode: Configurations

In case anyone hasn’t noticed, Xcode 2.1 shipped at WWDC on Monday. It includes a whole slew of new features. First and foremost is, of course, Intel support. Lots of people have said a whole lot about this so I won’t repeat it here.

The new feature that will have the most significant and immediate impact on developers’ lives is the switch from build styles to configurations.

In Xcode 2.0 and earlier, a build style was a collection of project-level settings that were overlaid on the settings for all targets in the project. For example, if you specified OTHER_CFLAGS="-DFOO=1" in a build style and OTHER_CFLAGS="-DFOO=0" in a target, the build style would take precedence when it was active and the compiler would be passed "-DFOO=0".

This was confusing: Build styles were edited by inspecting the target, and the OTHER_CFLAGS entry in the target settings showed up with a strikethrough when it was overridden in the active build style. This also caused problems for some developers who didn’t want settings from build styles overlaid on all targets in a project, and they particularly didn’t want settings from a build style in a project to override settings in targets in subprojects.

Configurations in Xcode 2.1 are just collections of settings. Settings in a target configuration override settings in the matching project configuration. Also, target configurations are by default self-contained, while project configurations default to being empty, which means by default you don’t have to worry about overriding at all. What’s more, configurations are applied by name when building subprojects — settings in the project you’re building don’t override subproject settings.

Editing build settings in Xcode 2.1 is a lot like editing build settings in Xcode 2.0 and earlier: You just select a target or the project and bring up its inspector, and build settings show up in the Build tab. You can select a configuration to edit, and you can even edit all configurations at once. This is very, very useful — often most of the settings for a target will be identical across Debug and Release configurations. The ones that aren’t show up in a mixed state.

(Did you notice I referred to Debug and Release configurations? That’s because Development and Deployment have been retired.)

You can even specify that a configuration is based on a text file of key/value pairs with the “.xcconfig” extension. So if you have collections of settings that you want to standardize on — for example, a suite of compiler error and warning flags — you can store them in files and check them into your source code control system separately from any projects. You can even copy or drag directly from the target/project inspector in Xcode and paste or drop in an xcconfig file!

Core Data: Generating an interface for an entity

The new Core Data framework and Xcode 2 modeling tools in Tiger are an extremely powerful way to develop great end-user applications quickly. You can even easily generate a human interface for your application that will let you work with its data model with little to no code.

To generate an interface, create an empty window in Interface Builder and make sure you’ll be able to see it with Xcode in front. Switch to your model in Xcode. Then just option-drag the entity you want an interface for into your window. Interface Builder will ask you whether you want an interface for one or many instances of that entity, and then generate a basic form-style human interface for all of the attributes and to-one relationships in that entity.

This generated interface isn’t a special monolithic “NSCoreDataControl” or anything of the sort. it’s composed of standard Cocoa controls that wired to standard Cocoa controllers via bindings. If your nib file’s owner is set to be an instance of NSPersistentDocument or a subclass, Interface Builder will even bind the controllers’ managed object contexts to the document’s.

If you just want to create controllers rather than full interfaces, or if you want to update the controllers in your nib file with the latest definition of your entity, drag the entity from your model straight to your nib’s document window. (That’s the one with the tabs for classes and instances etc.)

Note that none of this, none of this requires generating or writing code. You can create a new Core Data Document-based Application from the project template, create a data model for it in Xcode, create an interface for it in Interface Builder, and then build and run it. You can create, save, load, and manipulate documents and even undo and redo changes and avoid saving invalid data with no code.

Code Width

There’s a question on wrapping code at 80 columns in the Joel on Software Forum. Most of the time, when I see 80 columns as a standard it’s to enable easy printing of the code. However, in this day and age, why are you printing code? I print code occasionally when I need to read it in-depth, but other than that I do most of my reading on-screen. It’s certainly not a regular occurrence.

I also use mostly large or widescreen displays for coding. The smallest display I use regularly is my laptop, which is 1152 by 768. Most of the time I use my 19-inch monitor, which I run at 1600 by 1200. As a result, if I want to write really long lines, I can. But I don’t.

I generally limit the length of lines I write to 80 to 120 characters. Most of the time this is easy, because Objective-C’s syntax lends itself to very readable multi-line expressions:

NSDictionary *d = [NSDictionary dictionaryWithObject:@"Chris"
                                              forKey:@"name"];

The main reason I do it, though, is that I use multiple windows while I code. I usually have at least 6 windows open in Xcode while I’m coding: The Xcode project itself, the source and header file for the class I’m working on, the source and header file for the unit test I’m working on, and the build results window (which also shows my unit test results). Often it’s much more, with more class and unit test sources & headers open. And it’s much easier to fit these windows all on a screen when they don’t need to be as wide as the screen to see their contents…