51

I have a XCode4 / iOS project with a regular target and unit test target. Everything works fine, except when I try to #import one of my classes in my test class and try to use it. If I try to build the unit test target, I get the following link error:

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

In CategoryTests.m I'm importing the header file in this way:

#import "../todoro/FRRCategory.h"

What am I doing wrong?

cfischer
  • 23,024
  • 36
  • 125
  • 209

4 Answers4

165

Follow the instructions here. It doesn't require you to add any files to compile sources.

I first missed that "Symbols Hidden by Default=NO" should be for your app target, not test target.

It worked for me anyway (tm).

Martin Wickman
  • 18,530
  • 10
  • 71
  • 97
  • 1
    This the answer most people want to follow imo, not the one the questioner checked. This way the the application build product is build like for standalone use, and the tests link against it. The alternative is to replicate all build settings, linker settings, etc. to build the source separately with the unit test. – febeling Jul 20 '11 at 14:58
  • 3
    Lol, even after reading your comment I still messed up and needed the "Symbols Hidden by Default=NO" on my app target, not the test one. +1 – ColdLogic Aug 02 '11 at 17:09
  • it helps. And I found the sample code of Apple has the same settings.Thanks! – scorpiozj Sep 02 '11 at 03:15
  • It worked for me as well! I also think this is the only correct answer! Not the one marked as the correct one above... The one marked as correct is only a hack to get things kind of working. – Tom van Zummeren Apr 15 '12 at 13:14
  • 4
    This is indeed the only correct answer. The other answers compile two copies of your sources into what becomes the instantiated test bundle. While generally this will be fine, if there are bugs in the build-toolchain you would get very strange and hard-to-debug side-effects. – mxcl Oct 03 '12 at 13:53
  • Thank you, this is the first thing that helped! – Max Seelemann Jan 10 '13 at 13:50
  • Since the question specifically relates to Unit Testing, following the guide on the link contradicts Apple's one https://developer.apple.com/library/mac/#documentation/DeveloperTools/Conceptual/UnitTesting/02-Setting_Up_Unit_Tests_in_a_Project/setting_up.html#//apple_ref/doc/uid/TP40002143-CH3-SW1 – qnoid Feb 11 '13 at 16:10
  • While following the list of steps here, just make sure you add a cocoa touch test target (he says cocoa test target). had some issues with architecture type before adding the cocoa touch test target instead of cocoa test target – vpathak Oct 11 '14 at 11:58
  • The linked post above helped me to resolve this issue in Xcode 6.2 using the [Quick](https://github.com/Quick/Quick) framework for tests. In my case, only the BUNDLE_LOADER build setting had to be set. – phatblat Dec 10 '14 at 20:17
  • 1
    Symbols Hidden by default = NO for debug mode solved the problem even for X-Code 6.3 for my newly added test target. Thanks. – xySVerma May 14 '15 at 05:58
  • 1
    this solution does not seem to work for extension unit tests, more solutions are here: http://stackoverflow.com/questions/24627600 – yurgis Apr 14 '17 at 21:05
  • not work for me :( I have static library need to write unit test. Code compile and build successfully but test case fail unrecognized selector. It works fine when I add .m file in test target – Amit Battan Sep 04 '17 at 09:34
22

Make sure that the FRRCategory source file has been added to your Compile Sources for your unit test target.

Xcode 4:

Project Navigator -> "[Project Name]" -> Under Targets select your unit test target -> Build Phases -> Expand Compile Sources -> Click + at bottom of Compile sources and add the correct source file.

idmean
  • 13,418
  • 7
  • 47
  • 78
Joe
  • 55,599
  • 8
  • 122
  • 132
  • 1
    Adding the files to the compile sources removed the error. What are those "compile sources" anyway and what's the rationale of forcing you to manually adding files from your main target? – cfischer Apr 25 '11 at 22:22
  • 1
    Each target uses an independent set of source files. Either you didn't create the test target as a duplicate of your main target, or during the creation of `FRRCategory` you didn't select both targets. – Jano Apr 25 '11 at 22:46
  • 4
    It depends which unit testing framework you're using. Are you using SenTestingKit that comes with Xcode 4, or something else? …If you're using SenTestingKit, then you _don't_ want to add the code under test to your test target. – Jon Reid Apr 25 '11 at 23:02
  • Compile sources are all of your implementation files that you need to have compiled for a target. When you have multiple targets each maintains there own set of compile sources and when you go to add new or existing files to the project you should see a checkbox option for which targets that new file should be included in. This includes resources such as images and interfaces as well code. – Joe Apr 26 '11 at 12:28
  • 27
    This is not the correct answer to this issue imo. Check answer below this one. – carlos Jul 29 '11 at 02:38
  • This answer works, but is painful if you're testing more than a couple classes (which I hope you are). See @Martin Wickman's answer. – Robert Gowland Oct 17 '11 at 14:15
  • @Ertai I agree the answer below is now correct and I as well have upvoted it months ago. But do note the difference in dates between to the two answers. Maybe consider convincing the OP to accept the other answer rather than continually downvote this one. – Joe Mar 08 '12 at 14:00
  • the answer below is by far the best answer, especially if you have many sources – Hulvej Jul 09 '13 at 21:43
  • THIS IS THE WRONG ANSWER - see below. Don't mean this as rude to the answerer, just trying to save other people any wasted time in case they miss it. – nazbot May 12 '15 at 23:16
7

Another gotcha that you may hit is if your unit test is using C functions (or similar) that aren't used in the actual app.

This may be restricted to having a sub-project. In my case

  • App
    • Sub-project
      • A C library embedded (i.e. .c and .h files compiled directly inside)

My unit test used a few of the C functions that were not used anywhere else, and these were stripped from the app binary (NOT from the sub project's .a file).

The fix is to

  1. turn off "Dead Code Stripping" for the app's Debug build.* and
  2. make sure your unit tests are using Debug and not Release, in the Scheme settings.

(* don't do this to the release configs as it'll bloat the app with code that is never called).

Kalle
  • 12,846
  • 7
  • 58
  • 74
1

You should only refer to a folder inside your import if your file is inside a framework. Otherwise, once you added your file to the project, simply do #import "FRRCategory.h". Well, unless you did something weird with your Header Search Paths.

Jano
  • 60,366
  • 20
  • 152
  • 174