TestKit Documentation
Writing Unit tests
Any method and function call you write is eligible for a unit test. Consider writing a separate test for every unique behavior exhibited by your method/function.

For example, if you are testing setName:, and you've decided that nil is unacceptable, while any instance of NSString is fine, then write a testNullName method, which makes sure that setName: behaves one way when nil is passed in, and another way when a valid NSString is passed in.

Two common methods of grouping unit tests are by class and by state. Grouping tests by class makes it easy and convenient to find and create new tests. Grouping tests by state enables you to use a single Fixture to set up an object graph, and arrange your unit tests accordingly. Most test suites use a combination of methods depending on their needs. Use TWMockObject to help you concentrate on testing new code, and avoid duplicating exising tests. For example, if you're testing an auditing system, set up a fixture so that the accounts you are auditing are instances of TWMock. The goal is to concentrate your testing to the specific behavior of your Auditor, and avoid retesting Account.

Running Unit Tests
TestKit gives you the tools you need to run your tests automatically at each build, manually from TestRunner, or scripted ( or manually ) from TestRunnerHelper. If you want tests to run at each build, create your target by selecting the TestKit/TestBundle target.

While running all your tests during every build cycle is a great way to insure the integrity of the build, there are times when it is more productive to concentrate on a particular subset of your tests. To limit the tests that get run during the build, modify the 'Shell Script Files' of your build phase by specifying the fixture you are interested in:

./build/TestRunnerHelper -pb "./build/$PRODUCT_NAME.$WRAPPER_EXTENSION:MyTestClass"

You can specify certain test cases if you wish:

./build/TestRunnerHelper -pb "./build/$PRODUCT_NAME.$WRAPPER_EXTENSION:MyTestClass.testOne"

You can also specify multiple tests:

./build/TestRunnerHelper -pb "./build/$PRODUCT_NAME.$WRAPPER_EXTENSION:MyTestClass" \

Be sure to remove your specific test cases when you are finished modifying/debugging your code.

Debugging unit tests
If you prefer to use logging statements to debug your code, TestRunner conveniently separates stdout and stderr. You can use your own logging techniques, or add the line
#import <TestKit/TWLoggingMacros.h>
to your code, and use the macros defined inside. TestRunner creates a new Objective-C runtime and reloads your bundle every time you run your tests, so there is no need to restart TestRunner between builds. Deselecting passing tests is a convenient way to make sure that TestRunner is only executing the tests that need debugging.

If the debugger is more your style, you'll have to do a little set up for each project you wish to debug:

  1. Open the XCode project with targets you wish to debug
  2. Select Project->New Custom Executable
  3. Press 'Choose...' in the assistant dialog box
  4. Choose '/Applications/TestRunner/TestRunnerHelper'
  5. Fill in an executable name of your choosing
  6. Select the project you want to add it too
  7. Select 'Next'
  8. In the resulting editor, add the names of the test bundles you wish to debug to the 'launch arguments' list (myTests.bundle)

In order to debug a test bundle:

  1. Make sure the bundle you intend to debug is the current target. This insures that your source code is rebuilt if necessary
  2. Set breakpoints as you normally would
  3. Select your custom executable in the 'Groups & Files' view (Executables->TestRunnerHelper)
  4. In the 'Details' view (top right pane), make sure the radio button next to the TestRunnerHelper is selected. This ensures that TestRunnerHelper will be the main executable run when you select 'Debug->Run Executable'
  5. In the editor pane, make sure the launch argument representing your target bundle is selected, and that no other launch arguments are selected. This step ensures that your test bundle is passed to TestRunnerHelper on the command line

You can be more specific in your launch arguments to save execution time:

myTests.bundle:MyTestClass.testOne specifies a specific test to debug