Menu

Unit_Tests Log in to Edit

GregJefferis
Attachments

Introduction

Unit Testing is a good way to ensure the integrity of your code by

  • providing tests to ensure that new code behaves as expected (eg in edge cases)
  • providing a way to test that new code doesn't break the logic in old code
  • in so doing it provides a form of developer documentation

For this to work in practice, it must be easy to run existing tests (so that this is always done before committing) and easy to add new tests.

Bibdesk

BibDesk had unit tests for a few core components written by Mike McCracken but they seem to have been moribund since about 2005. They used the UnitKit framework but this is no longer under development. Around that time Apple decided to adopt OCUnit aka SenTesting Unit Test framework and it is now distributed with Xcode >=2.1. We are now reviving the use of Unit Testing by

  1. Setting up the Bibdesk project with a UnitTests target for the new OCUnit framework
  2. converting existing tests where possible to the new framework
  3. Writing new tests

In terms of where to focus on for new tests Adam Maxwell wrote as follows on the developer list:

> I think this would be very useful as well, especially for classes that deal with parsing (BibAuthor, *Parser, BDSKComplexString, NSString category etc.) since breakage there is a critical problem. Currently there's really no guarantee that anything has been tested, unless the committer tested it...and sometimes that minor cleanup between the last test and the actual commit can be disastrous (BTDT).

Implementation

I have implemented the new Unit Tests framework exactly as described in this blog post by Bill Dudney. There is also information on Apple's developer site.

Basically there is a new UnitTests target that is dependent on the main BibDesk target. If you build that target then you build AND run the unit tests. This should be what the project looks like when you fetch from svn.

Debugging

You can also debug the unit tests. To do this you need to add some options to the BibDesk executable that are also described on Bill's blog. I couldn't get these to stick because they are not stored in the main project.pbxproj file but in my personal jefferis.pbxuser file. So for the moment you will have to add yourself (unless perhaps Mike McCracken or one of the other developers wishes to update the mike.pbxuser file). They are as follows:

argument

 -SenTest All

environment variables

XCInjectBundle: UnitTests.octest
XCInjectBundleInto: $(BUILT_PRODUCTS_DIR)/BibDesk.app/Contents/MacOS/BibDesk
DYLD_INSERT_LIBRARIES: $(DEVELOPER_LIBRARY_DIR)/PrivateFrameworks/DevToolsBundleInjection.framework/DevToolsBundleInjection
DYLD_FALLBACK_FRAMEWORK_PATH: $(DEVELOPER_LIBRARY_DIR)/Frameworks

Note that Xcode >3.1 appears to require the XCInjectBundleInto environment variable which was not required in 3.0.

To do this choose the BibDesk executable Right click, Get Info and then make the Arguments tab look like this:

Contributing

To add new tests

  1. Go to the UnitTests file group at the top of the project
  2. Right click and
  3. Add ... New File ... Cocoa Objective-C test case class
  4. Save this in the UnitTests subdirectory (bibdesk/UnitTests)
  5. giving it a name like TestBDSKClass.m

Look at the existing tests for more code details. Any method called test will be run. You will of course need to #import header files for the classes you are testing. If you reuse an object in multiple tests you can make it in the special setUp method and release it in the special tearDown method. TestUnitTest.m is the most basic example of a test. Basically you specify the logic that you want to insist on by using an STAssert** macro of the form:

 STAssertEquals(4+5, 9, @"should make 9");

Related

Wiki: BuildingFromSVN
Wiki: Developer_Information