Following Chris Hanson's blogs and Apple's Automated Unit Testing with Xcode 3 and Objective-C I have started implementing unit tests for my projects. However, I use a lot of plug-ins (loadable bundles) and I can't quite figure out how to test them.
I figured I would use the approach Chris Hanson described for testing frameworks. I started with a Cocoa Bundle project, added a principal class and changed the type to plugin. Then I added the unit test 开发者_C百科bundle, add the plugin as a direct dependency (Apple's instructions) and set the following build settings:Bundle Loader: $(BUILT_PRODUCTS_DIR)/CocoaPlugin.plugin/Contents/MacOS/CocoaPlugin
Test Host: $(BUNDLE_LOADER)The problem is that as soon as I've done that and build the test target, I get this message:
error: Test host '/Users/elisevanlooij/Documents/Plug-ins/CocoaPlugin/build/DebugCocoaPlugin.plugin/Contents/MacOS/CocoaPlugin' exited abnormally with code 127 (it may have crashed). [code 126 in another plugin]
I had hoped that adding the otest custom executable would help, but unfortunately not. I really hope someone can help because not being able to unit test my plugin really puts a cramp in my testing lifestyle.
Take a step back. Your Bundle Loader setting is erroneous and adding a custom executable is not going to affect compilation of a unit-test bundle.
You need to get your unit-test bundle to build without errors (and warnings!), and your tests will run automatically (you do have at least one valid SenTestCase class with at least one valid test method, right?).
So, are you saying that your test-bundle compiles without warnings and you have written some tests using classes and methods from your plugin? If so you must have some how taken care of loading the plugin-bundle into the unit-test-bundle and defining some kind of API, as the plugin-bundle doesn't have any public headers, right?
see Apple docs here
Loading plugins into plugins (essentially what you are trying to do) is not easy and they are not magically 'linked' at compile time like the frameworks in the Chris Hanson Blog that you refer too. They wouldn't be plugins if they were.
The simplest way to go is to not actually test your plugin at all but add the files you want to test directly to the unit-test bundle. At least this way you can get on with testing your code without fiddling about with dynamically loading bundles.
But if this isn't satisfactory, you can get what you are trying to do to work with a little effort - you should definitely add tests to verify that your plugin is loaded and that the symbols you think are available REALLY are available. Once your tests build ok you should follow Chris Hanson's other excellent blog on debugging unit test bundles showing you how to step thru your tests in the debugger - you should be able to track down any errors.
Your
Bundle Loader: $(BUILT_PRODUCTS_DIR)/CocoaPlugin.plugin/Contents/MacOS/CocoaPlugin
is correct. It means that when linking your test bundle you do not include the classes under test there, and they will be looked up from CocoaPlugin. It is a compile time setting and should cause your test bundle to compile/link sucesfully. (See -bundle_loader in man ld)
Your
Test Host: $(BUNDLE_LOADER)
is incorrect. Your test host should be either an application (with a NSApplicationMain called from main method) or not set. This TEST_HOST setting is a runtime setting to run your unit tests. You basically have two options:
Do not set TEST_HOST, and load your plugin from your test bundle. For example you can do this using the initlaize method.
Create a dummy test_host application that will load your plugin, and then call NSApplicationMain, and use this app as your TEST_HOST.
The +initalize
method for your test bundle to load the plugin would look like this:
+ (void)initialize
{
NSBundle* bundle = [NSBundle bundleWithPath:pathToPlugin];
[bundle load];
NSLog(@"Loaded:%@\n",bundle);
}
The main method in your dummy_test host app can look like this:
int main(int argc,const char** argv)
{
NSBundle* bundle = [NSBundle bundleWithPath:pathToPlugin];
[bundle load];
NSLog(@"Loaded:%@\n",bundle);
return NSApplicationMain(argc,argv);
}
Other ideas for testing plugins:
- use an independent bundle: Do not specify either BUNDLE_LOADER or TEST_HOST and put your classes from the plugin also into the unittest bundle.
- put your test cases into the plugin, and try to get that unittest. Just weak link SenTestingKit to your plugin and add a script phase with:
TEST_RIG=/Developer/Tools/otest "${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests"
.
精彩评论