Unit Testing a Bundle in Xcode, Part 3
In part 2, I explained how to test a bundle by using a custom script in the "Run Script Phase". A slightly better approach is to use a test rig. From the Xcode documentation, a test rig is:
A tool that can take information from its environment and will be passed the path to a unit test bundle as its sole argument.
In part 2, the BundleTestRunner
took two arguments, so it cannot be used as a test rig. This entry describes how to modify it so it takes one argument, and the rest of the information from the environment.
Instead of passing the bundle to pre-load as a command line argument, BundleTestRunner
will get this information from an environment variable: TEST_LOAD_BUNDLE
. Here's the new main method:
int main(int argc, char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSBundle * bundle;
NSString * bundlePath = [[[NSProcessInfo processInfo] environment]
objectForKey: @"TEST_LOAD_BUNDLE"];
if (bundlePath != nil)
{
loadBundle(bundlePath);
}
bundlePath =
[[[NSProcessInfo processInfo] arguments] objectAtIndex: 1];
loadBundle(bundlePath);
SenTestSuite * suite;
suite = [SenTestSuite testSuiteForBundlePath: bundlePath];
BOOL hasFailed = ![[suite run] hasSucceeded];
[pool release];
return ((int) hasFailed);
return 0;
}
I've not included the the loadBundle()
function. It just loads a bundle or throws an exception and can be found in BundleTestRunner.m
. Since this version now uses exceptions, Objective-C exception handling must be enabled. Here is a summary of the custom settings needed for BundleTestRunner
:
Build Setting | Value |
---|---|
Zero Link | Off |
Other Linker Flags |
-framework'Foundation
|
Enable Objective-C Exceptions | On |
For the unit test bundle, I still assume you are testing against MyBundle.bundle
. Instead of editing the script in the "Run Script Phase", you will leave that as the default. All changes can now be done with build settings. Here is a summary of the changes:
Build Setting | Value |
---|---|
Bundle Loader | $(BUILT_PRODUCTS_DIR)/MyBundle.bundle/Contents/MacOS/MyBundle |
Test Rig | ${BUILT_PRODUCTS_DIR}/BundleTestRunner |
TEST_LOAD_BUNDLE | ${BUILT_PRODUCTS_DIR}/MyBundle.bundle |
The last setting, TEST_LOAD_BUNDLE
, is a custom build setting, which can be added by clicking the Plus ("+") button. Custom build settings are turned into environment variables, which is how it gets passed to BundleTestRunner
.
And that's all! With these build settings, you should now be able to build the unit test bundle and have the tests run as part of the build phase. A possible improvement is to have TEST_LOAD_BUNDLE
be a colon separated list of bundles to load, so BundleTestRunner
could pre-load multiple bundles. This is probably not a common case, so it's not worth the effort.