23

I want to write some logic unit tests for classes in my XCode application. In Xcode 4, I clicked on the project name in the Project Navigator, and from the bottom clicked Add Target. I chose "Cocoa Touch Unit Testing Bundle" under Other, give the new target a "product name" of "tests", and finish.

Because the class I want to test is compiled as part of my existing application target, for my new "tests" target I immediately go to the Build Phases tab and add my existing application target as the only target dependency.

I then go to the created tests.m file, import the class I want to test (below it's ReleasePlanManager, and call one of its methods. But the linker fails with an error like:

Undefined symbols for architecture i386:
  "_OBJC_CLASS_$_ReleasePlanManager", referenced from:
      objc-class-ref in tests.o
ld: symbol(s) not found for architecture i386
collect2: ld returned 1 exit status

So the class cannot be found, even though (from my understanding) adding the application target (which it is a part of) should be sufficient?

Any help would be greatly appreciated. Thanks!

shadowmatter
  • 1,352
  • 2
  • 18
  • 30

1 Answers1

33

Your test bundle needs extra settings:

  • Set Bundle Loader to $(BUILT_PRODUCTS_DIR)/AppName.app/AppName (replacing AppName in both places with your app's name)
  • Set Test Host to $(BUNDLE_LOADER)

(If you create a project from scratch and enable unit tests, these are set up for you. But if you add a unit test bundle to an existing project, they're not.)

Jon Reid
  • 20,545
  • 2
  • 64
  • 95
  • 24
    It's also worth noting that your host application target must not be configured for **"Symbols Hidden by Default"** (in the **Code Generation** section of Build Settings) for the Configuration you execute your tests against. This just tripped me up earlier today on an older application. – Blake Watters Jan 11 '12 at 21:04
  • I followed your and Blake Watters’ suggestions, now it gives me: -bundle_loader can only be used with -bundle, any ideas? –  Apr 30 '12 at 08:55
  • (may be I am facing this because I am using GHUnit and not SenTestingKit?) - for now I am including the required sources to both main target and test target. –  Apr 30 '12 at 09:03
  • (sorry for spamming) looking here http://stackoverflow.com/questions/2610670/gh-unit-for-unit-testing-objective-c-code-why-am-i-getting-linking-errors, I think adding sources to both targets is the only solution, which is something I really don’t want to do –  Apr 30 '12 at 09:12
  • 1
    @ishaq, that other answer predates Xcode 4's support for injecting tests into an app. I don't use GHUnit but can't believe it would miss this feature. It sounds like your test target may be the wrong type. I'd try to re-create it from scratch, making sure to select Unit Testing Bundle. Then see if you can get one test working that depends on a class in your app. – Jon Reid Apr 30 '12 at 14:39
  • @JonReid too bad, I can’t use Unit Test Bundle target type, GHUnit requires target type to be some sort of application (since it has its own GUI, which is one of the features I want). adding sources to both main target and test target :/ –  May 01 '12 at 06:13
  • 1
    @BlakeWatters You rock!! Indeed setting **"Symbols Hidden by Default"** to **NO** did the trick! (Docs say it is YES by default) – nacho4d May 01 '12 at 10:29
  • Another thing to note in Xcode 4 is that there are 2 columns to set build settings. Make sure to set it on the target, not the project – xster Jul 04 '12 at 16:08
  • @ishaq did you ever figure out how to get around this? regarding the GHUnit? – mkral Jan 15 '13 at 21:41
  • @mkral no :( I ended up including sources to both targets. –  Jan 24 '13 at 06:07