Xcode 3.1.3 problems unit-testing a plug-in - cocoa

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 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".

Related

How can I debug Ginkgo tests in VS Code?

I'm evaluating ginkgo at the moment - I very much like the BDD style.
However I'm unable at the moment to get the VS Code debugger to work with the framework. The official VS-Code extension provides test-by-test debugging for native go tests using CodeLens. With other languages and frameworks (eg Typescript/Mocha), I've been able to debug individual test files by setting up launch.json appropriately, but have been unable to find suitable examples for go.
Does anybody have any examples of any launch.json setups for debugging ginkgo tests (or go code invoked from any other framework)?
Thanks!
After a bit of playing around I found a way forward which perhaps should have been obvious. In case it isn't I'll leave the question and this answer here:
For a package foo, a foo_suite_test.go file is generated by the gingko bootstrap command. This contains a top-level test called TestFoo which runs the rest of the tests within the package.
This does have a CodeLens run test | debug test section above it which you can use to debug the entire suite.
It's not quite as convenient as the individual CodeLens entries which appear over each native go test, but it's easy enough to isolate specific tests to run using the Gingko F prefix.

Unit tests failing without any message if linked to a custom framework

Update (From Build log):
"The bundle “Lib2Tests” couldn’t be loaded because it is damaged or missing necessary resources."
(dlopen_preflight(/Users/abc/Library/Developer/Xcode/DerivedData/Lib2-gaplfrtqethacsgkmjmlivcyuity/Build/Products/Debug-iphonesimulator/Lib2Tests.xctest/Lib2Tests):
Library not loaded: #rpath/Lib1.framework/Lib1
It seems the lib2.framework project only linked the Lib1.framework and it didn't embed it, and there's no option to embed the framework inside another cocoa touch framework, that's why at the end unit test failed as it couldn't find the referenced Lib1.framework.
put simply if FrameworkB is dependent on FrameworkA for some functionality down the road, UnitTests of FrameworkB will cease to run - if FrameworkA is linked to FrameworkB
Setup
I've created a simple isolated case to demonstrate and reproduce the problem.
I've 2 Swift Cocoa Touch Frameworks (Lib1 & Lib2 - Lib2 is dependent on Lib1 - single swift file with single unit test in each)
Lib2 unit tests will only work if you remove the linked Lib1. Interestingly both projects works on their own if run independently.
Question: is this a bug in Xcode? any workarounds?
Smallest Reproducible Example Project: https://www.dropbox.com/s/kycnvt1qvz8zw4o/LibTest.zip?dl=0
I'm attaching a screenshot, it's weird, no error messages or failure details in the console, all I get is a notification on the side the unit test failed. The test is not complicated, single line instantiating a class and it's runs successfully if I remove the link to my custom framework. (the custom framework itself also simple and runs/tests successfully on it's own) To observer this behavior simply delete the linked framework from the project files and run "Test" again. I believe the error is related to project files settings etc. and the solution requires to look into project file itself.

Adding compile sources to Xcode Unit Tests (Application vs Logic)

It seems that Logic tests require that I add application files (.m and .h) to the compile target of the test along with the test .m files. I think that this is because Application tests actually load the app side by side with the tests but I am not sure.
Is the bundle loader 'the difference' between Application and Logic tests? I am not talking about why to use them but the distinction between how they work and what they do.
Here you can find a nice description of the tests, with what they do and how they differ. Also, in the next section here, you can read about how to set them up, which reveals the technical differences between them. As you suggested, loading the app bundle seems to make the difference.
Edit: Seems that the links above no longer work, I found a legacy document here: https://developer.apple.com/legacy/library/documentation/DeveloperTools/Conceptual/UnitTesting/UnitTesting.pdf

How do I add a target to a test scheme?

I have configured unit testing for a project, and I need to use the classes that are in the run scheme also in the test scheme.
This because if I try to use a class that I use in the run scheme, I get a linker error, the linker does not recognize that (user defined) class.
I called the test bundle "TestBundle", I am able to test the application unless I use other classes. This is what I see when I try to edit the test scheme:
It seems like there isn't a place for adding another target, how do I do that?
schemes RUN targets... they don't manage what a target is made up of.
they could also be called 'environments' or 'execution setups' or so :)
targets are managed under your project (when you click onto the blue project icon in the project navigator)
note: I think that apple brought us schemes only to haze us ;D

Unit testing in Xcode 3.1

I read the question on 'The best way to unit test Objective-C and followed the instructions, but no matter what I do, the Unit tests do not run. Actually the entire program does not run, I get the following message.
dyld: Library not loaded: #rpath/SenTestingKit.framework/Versions/A/SenTestingKit Referenced from /Users/garethlewis/work/objc/UnitTesting/build/Debug/UnitTesting
Reason: image not found
I have set the DYLD_FALLBACK_FRAMEWORK_PATH variable, and also the XCInjectBundle as well as the DYLD_INSERT_LIBRARIES and added the variable -SenTest All.
I can't have the only installation of Xcode 3.1 that Unit testing fails on.
Can someone who has managed to get Unit Testing on Xcode 3.1 working give some details on what needs to be done. It would help so much, with what I am trying to do.
You don't need to do this stuff to just run your tests.
If you're writing tests for an application, you should just need to set the Test Host and Bundle Loader build settings for your unit test bundle target and they will be run as part of your build. If you're writing tests for a framework you don't even need to do that, just make sure your test bundle links against your framework.
I assume you're actually talking about debugging your tests, not just running them. If so, it's important to give us the following information:
what kind of tests — application or framework — you're trying to debug
what environment variables you set, and what values you set them to
what arguments you set (-SenTest All should be an argument, not environment variable)
what the full error shown in your debug console is, not just the specific failure
That will help diagnose what's going on.
At first glance, it looks like you might have a typo in your DYLD_FALLBACK_FRAMEWORK_PATH because that determines where dyld will look for the SenTestingKit.framework binary if #rpath cannot be resolved. Knowing what it's set to will probably help.
(PS - It's Xcode.)

Resources