Unit Testing in Objective-C


Having been recently exposed to unit testing in C#, I started wondering whether unit testing frameworks were available for my Mac work in Objective-C. So far, I've found 4 frameworks for doing the unit testing itself, and 1 just for the creation of mock objects. The unit testing frameworks, in no particular order, are ObjcUnit, OCUnit, TestKit, and UnitKit; the mock object implementation is OCMock...


ObjcUnit and TestKit claim heritage from Java's JUnit, and OCUnit is based on Smalltalk's SUnit, making it a sibling of sorts to JUnit. UnitKit doesn't discuss it's ancestry on the home page, but on the first page of its documentation it pays respect to the other three frameworks, then asks "Why on earth would the world need another unit testing framework for Objective-C...?" The document gives several answers, one of which is "...UnitKit strives to be less (or maybe more) than a clone of JUnit or SUnit... it is an attempt to rethink how a basic testing framework can be put together that leverages what Objective-C is, and is not, as a language." One small example is the absence of the setUp and tearDown methods one might expect; Objective-C already has these covered with init and dealloc, so UnitKit doesn't provide them.

In time, I may try two or more of these frameworks. But one needs to start somewhere, and based on UnitKit's appealing pitch and simple documentation, I decided to start by downloading and installing UnitKit. I'm still very new to unit testing, so for the moment simple is better.

UnitKit installs easily with a double-click of UnitKit.pkg, though should you want it source is also provided in the distribution. Once installed, it's integrated with Apple's excellent (and free) XCode IDE; there is no separate GUI app for running your unit tests. If you later decide that UnitKit isn't quite what you wanted, the authors have provided a painless uninstall script.

It takes only minutes to add unit testing into a new or existing project. Essentially, you add a new target bundle to your application, add the UnitKit.framework to it, and start adding your unit test classes. Building the unit test target tests the app and reports results. If you make your primary bundle dependent on the unit test bundle, then your unit tests run whenever you build your app. Test failures are reported the same as any other error in XCode: click on the error line and you'll be taken to the test that failed. The process really couldn't be much simpler, and the UnitKit manual walks you through a step-by-step tutorial. The only place the tutorial tripped up was in directing me to a Project > Add Frameworks menu that doesn't seem to exist in XCode 1.5... but really, all one needs to do is Ctrl-click on the Frameworks in the Groups & Files tree, then select Add > Existing Frameworks and navigate to /Library/Frameworks/UnitKit.framework.

That, of course, leaves the real work of writing the unit tests themselves. If you're adding unit testing to an existing application, that may mean you'll be doing some rewriting to make the app more easily testable. It's much easier to build unit testing in from the start!

I still haven't dug into mocking in Objective-C, which proves that I haven't actually used UnitKit much yet. TestKit and ObjcUnit both come with support for writing mock objects, and OCUnit suggests the use of OCMock. UnitKit's website and documentation are silent on the subject of mock objects --- special test objects designed to mimic an environment for a class under test --- but OCMock should fit in with UnitKit, too. That's probably the next avenue I'll be exploring.

Er, in my spare time.

Meanwhile, if you prefer a framework other than UnitKit for Objective-C work, please drop me an email and let me know what its advantages are. For an article that deals with using OCUnit in a Cocoa project, see Jim Menard's Unit Testing with OCUnit on MacDevCenter.com.

Posted: Fri - March 18, 2005 at 06:58 PM          


©