When Do App Sources Need to Be Included in Test Targets

When do app sources need to be included in test targets?

I spent some time figuring this out.

If you read this documentation you find that Xcode has two modes for running tests. Logic Tests and Application Tests. The difference is Logic tests build their own target with your Classes and symbols built right in. The resulting executable can be run in the simulator and reports test output back to Xcode. Application tests on the other hand build a dynamic library linking to your code which is injected into the app at runtime. This allows you to run tests in iPhone environment and test Xib loading and other things.

Because the symbols are missing from your test target when you unlink the source files it appears your older project seems to have a test target configured for logic tests, not Application (unit) tests.

As these days Xcode seems to be trying not to distinguish between the two and defaults to creating an Application Tests target lets walk through all the things you might have to change to turn your Logic Test Target into a unit test one.

I'm also going to assume that you have an Application Target and not a static library target as the directions will be a little different.

  1. In the build settings for your test target delete "Bundle Loader" and "Test Host" build settings. We will get Xcode to add these back later
  2. You need to remove all the .m files from your application from the test target. You can either do this by selecting all the .m files and removing the test target in the Xcode File inspector or you can use the compile sources build phase of the test target.
  3. Change the "Framework search paths" for your test target. For Xcode 5 they should be
    $(SDKROOT)/Developer/Library/Frameworks
    $(inherited)
    $(DEVELOPER_FRAMEWORKS_DIR)
    in that order and with no extra quotes or backslashes
  4. Go to the General pane of your test target's build settings and select your target from the drop down menu. If the menu already specifies your application target you should toggle it off and on again. This will make Xcode reconfigure the Bundle loader and Test Host settings with the correct value.
  5. Finally double check your application's scheme. In the scheme drop down select edit scheme. Then click the test action. Make sure you test target is in the list on the info pane and make sure all the tests are selected.

This information more or less comes from the above linked documentation, but I updated the steps for Xcode 5.

EDIT:

Hmm 100% note what eph515 is saying about debug symbols being visible but you might also want to check that someone didn't set your scheme's test action to build in the Release or other configuration. Click the scheme selector an choose edit scheme. Click the test action and then make sure the Build Configuration is Debug

build configuration screen for test action in a scheme

If you have a Static Library Target

So if you have a static library target you have two options:
1. Logic Tests
2. Application tests in a host app

For 1. you have to make sure that Bundle Loader and Test Host are empty for your static library target. Your sources then have to be compiled into the test target as they would have no other way to be run.

For 2. You need to make a new app Project in Xcode and add your static Library project as a subproject. You then need to manually copy the Bundle Loader and Test Host build settings from your New App's test target to your Static Lib test target. Then you open the scheme for your new Test App and add your test target to the tests action for the new app.
To run the tests on your lib you run the test action for your host app.

How do iOS Unit/Application-Test targets link against classes from their host app?

I've just realized I haven't answered this question...

In my case the missing symbols was a result of compiling the libraries with visibility set to hidden. If that is the case, the tests are unable to find the symbols as the lib does not provide them to the public. Changing the compile command for testing to set the visibility to default made the difference.

Effectively sharing test doubles between separate test targets

A) (As you point out) Extract a framework containing the doubles.

or

B) Simply add the files to each test bundle. That is, they would be the same files underneath.

The advantage of B is its simplicity. One disadvantage is that, if you build each test bundle, you will end up building these test doubles twice.

Testing two targets with same tests

After some time I found out that what I needed was different targets.

These are my targets now:

  1. The app target
  2. The new app (new branding)
  3. Unit tests target (host app >> 1.)
  4. UI tests target (target app >> 1.)
  5. Unit tests target (host app >> 2.)
  6. UI tests target (target app >> 2.)

do I need to manually add each *.m file to my unit test target when it's needed?

Yes, you will need to add each and every .m file you need to your unit test target.

This will include them in the target compile and link phases.



Related Topics



Leave a reply



Submit