Setting up for Unit Testing

In my last post I talked about how to setup for Code Coverage and made a reference to unit testing. In this article I wanted to share my experience with setting up to run unit testing.

A great place to start is the Apple document Xcode Unit Testing Guide.

Setup target and initial test suite

Choose File > New > Target …
In the iOS section, select Other, then select the Cocoa Touch Unit Testing Bundle template.

Cocoa Touch Unit Testing Bundle template

Since my app is called ContactsOnline, I’ll name my product (new target) ContactsOnlineBasicUnitTests.

This creates a test suite by the same name ContactsOnlineBasicUnitTests.m, within a group called ContactsOnlineBasicUnitTests.

Unit-test targets define one or more test suites.

Adding test suites

If I wanted to add additional test suites, I could right click on the group name ContactsOnlineBasicUnitTests and then:

Select New File …
Choose Objective-C test case class.

Select the Target when prompted (i.e. ContactsOnlineBasicUnitTests).

New test suite target

Scheme

See my previous article where I talked about Code Coverage.
For unit testing I will create a new Scheme copied from the Coverage Scheme and call it UnitTestsAndCoverage.

Edit the Scheme and go to the Test tab. Click the + to add the ContactsOnlineBasicUnitTests target.

Expanding this target will show the test suites included.

As new suites are added, they will automatically show up in the expansion of the target.

unit test scheme test phase

Compile Sources, Libraries, Resources

Add in just the unit test code for the compile sources.

Add in all the libraries used in the original application.

I did not need to specify any resources.

Application versus Logic tests

Apple distinguishes between Logic and Application tests.  Logic tests check the correct functionality of a unit of code by itself (not in an app).    Application tests check units of code in the context of your app.  I will focus on the latter.

I setup for Application tests by following instructions in the document section  Setting Up Application Unit Tests.

The three main pieces to this setup are:

1.  Set the Bundle Loader: $(BUILT_PRODUCTS_DIR)/ContactsOnline.app/ContactsOnline

2. Set the Test Host: $(BUNDLE_LOADER)

3. Make this target dependent on the target that builds your app.
In Target Dependencies, my test target (ContactsOnlineBasicUnitTests) should have one dependency on the app (ContactsOnline).

unit test target dependency

Use Xcode 6.1 Simulator

The deployment target can be 5.1 if you wish, but I found that the simulator must be 6.1 for unit testing.

With the 5.1 simulator I was seeing errors with the signatures: Error loading …, Library not loaded: …, Error loading bundle …

I noted from some searching that others have seen similar errors.

Running

Running a unit test is simple.  Select the Scheme and device. Select “Test” from Run menu.

All suites in the target are run.

Not that it should make any difference, but I noted that test cases are executed in alphabetical order, that is “testCase2” comes after “testCase1”.

Coverage

In order to generate coverage results, I needed to perform an additional step beyond just copying my unit test scheme (UnitTestsAndCoverage) from my Coverage scheme.

I need to make the same addition to the .plist file that was described in my Code Coverage article, namely adding the key “Application does not run in background” and setting it to YES.

Profiling: Invalid Magic Number

I started getting warnings such as “profiling: invalid magic number”  and  “profiling: invalid number of counters” when I would change any code and re-run my unit tests.   After some digging, I found that this had to do with an attempt to merge coverage results from successive runs.   Performing a “build clean” before a run would eliminate these warnings, but that was rather tedious.

I ran across a nice article that had a much better solution:

How to Fix ‘Profiling: Invalid Magic Number’ in Xcode 4.6 When ‘Generate Test Coverage Files’ is enabled

The author’s fix was to add a build script that cleans out the gcda and gcno files on every build.    In my experiments I found that cleaning out the .gcda files was sufficient, and that I didn’t want to remove the .gcno files in any case since they weren’t getting regenerated after the script ran (but the .gcda files did).

I also needed to change how I referenced the .gcda files for the remove.   I have two targets – ContactsOnline and  ContactsOnlineBasicUnitTests.   The .gcda files of interest are in a directory related to the former, but the environment variable OBJECT_FILE_DIR_normal is pointing to the latter.   Some wildcard magic worked here (I’ll remove .gcda files for both targets).

echo "Cleaning Profiler Information"

cd "${OBJECT_FILE_DIR_normal}"
cd ../..

# We need to delete *.gcda files in both the unit test and app directories.
rm -f */Objects-normal/${CURRENT_ARCH}/*.gcda

# Do NOT remove *.gcno files, as they will not regenerated after the remove.

SenTestCase Flow

The last thing I wanted to share was a post that talked about the unit testing flow with SenTest  SenTestKit: cleaning up after ALL tests have run?

One of the answers made the observation that there also exists class methods + (void)setUp and +(void)tearDown which are invoked once at the start and end of the test suite run.

I actually found a good use for these class methods which I will discuss in a future post.

Advertisements

4 responses to “Setting up for Unit Testing

  1. Pingback: How to Fix ‘Profiling: Invalid Magic Number’ in Xcode 4.6 When ‘Generate Test Coverage Files’ is enabled « Dave Meehan

  2. Scott, thanks for the trackback on my post, glad it helped you out. You amendment actually got me to realise why I was still seeing error messages on subsequent builds, and so I’ve now revised the post to give cleared instructions. Thanks!

    Like

  3. Hi Dave – glad we were able to help each other out 🙂

    Like

  4. Pingback: The development of Contacts2Web | Finalize.com: My journey with iOS and other code adventures

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s