Debugging Unit Tests for the iPhone/iPad

Update 8/17/2010

I changed the Environment Variable arguments to make it easier and remove the unnecessary quotes around the directories. I now just use the SDK_ROOT for both DYLD_FRAMEWORK_PATH and DYLD_LIBRARY_PATH variables.

I have been working my way through a new iPhone app. I have been doing this TDD. One problem that I ran into was one of my tests failed, yet I could not figure out how to get it working easily so I wanted to debug my Unit Tests. This should be straight forward, yet it took me a while to figure out using the metaphors and tools of XCode (built in OCTest). I know that many people will say I should use GHUnit or GTM (Google Toolbox for Mac). I have tried both of these and I really don’t like them because they don’t feel as integrated into XCode (not that any of these tools do but that is another story). I spent a good bit of time searching around for how to do this for iPhone/iPad apps. The following articles are the best I found (although didn’t answer the questions completely):

After reading through these articles and many others I finally came up with the solution. I am using 3.2.3. Most of these articles are talking about earlier versions of XCode. Most of the solutions work (especially the last one). My biggest problem that I wanted to solve is make sure that when I switched SDK (iPhone 4 to iPad 3.2), the custom executable (more on this in a minute), otest, that I used was for the right SDK. Unfortunately, each SDK (Mac OS X 10.x, iPhone and iPad) have their own version of otest. So if I wanted to debug a universal iPad/iPhone application, I needed to point to the right otest.

When you create a UnitTest bundle in XCode, it runs a script to run the Unit Tests when you build that target. If you look at this script (/Developer/Tools/RunUnitTests), you will notice that it figures out what platform you are building for and then calls the RunPlatformUnitTests script. If you go to Terminal and do find /Developer -name RunPlatformUnitTests, you will see that there is one for each platform. Each one of these set specific environment variables and run the correct otest with the bundle passed into the script. Armed with this information and the information I got from the articles I could setup my environment to debug unit tests now.

How to Setup XCode

The first thing I did was add a custom executable to my project (that already had a UnitTest bundle target). I named it otest and pointed it to the otest for the iPhone 4 SDK (you could pick the one for iPad if you want). If you do a find for otest in the Developer directory (find /Developer -name otest) you will see that for each SDK, it is located in the Developer/user/bin/ folder. This was the important part of the puzzle. When you open the general table of your Custom Executable information windows, you will see a drop down for Path Type. Instead of Absolute Path you set this to Relative to Current SDK. This will then allow you to run the corrent otest depending on what SDK you pick.

General

Once you have this part, the rest is just setting the environment variables and the arguments for otest. You will need to pass the name of your unit test bundle (mine is UnitTests.octest). Optionally you could pass what test(s) you want to run, but I take the default to run them all. The only thing about the environment variables is that you will need to use quotes if there are spaces when things get expanded. I am not going to try and discuss each one, I leave that as an exercise for the reader. Here is the setup I have:

Arguments

Once this is setup, you can debug your Unit Tests. As mentioned in the Grokking Cocoa article, you can clone your unit test bundle and remove the run script so you can build and debug at the same time, I don’t ever do this. If your tests fail after building, you can just do a run debug and still debug without building again. I find this easier than managing another target.

Name Value
DYLD_ROOT_PATH $(SDKROOT)
DYLD_FRAMEWORK_PATH ${BUILD_PRODUCTS_DIR}:${SDK_ROOT}:${DYLD_FRAMEWORK_PATH}
IPHONE_SIMULATOR_ROOT $(SDKROOT)
CFFIXED_USER_HOME $(HOME)/Library/Application Support/iPhone Simulator/User/
OBJC_DISABLE_GC YES
DYLD_LIBRARY_PATH ${BUILD_PRODUCTS_DIR}:${SDK_ROOT}:${DYLD_LIBRARY_PATH}
DYLD_NEW_LOCAL_SHARED_REGIONS YES
DYLD_NO_FIX_PREBINDING YES

Hope someone finds this a useful.

Listened to: Become The Catalyst from the album “The Fall Of Ideals” by All That Remains

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Scott Densmore

A transplant from Seattle to Florida trying to bring some community love to the sunshine state. And don't call me a hippie.
This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Jeremy

    Thank you thank you thank you!

    I was struggling to get my debuggable target going again but this post helped fix it.

    How did you figure out what environment variables to use?

  • http://www.lostechies.com/members/scottdensmore/default.aspx Scott Densmore

    I looked in the shell scripts that are run by the UnitTest bundle. You can look in RunUnitTests and then follow it to RunPlatformUniitTests. It has all the Environment Vars to set in all the those scripts.

  • Mark Brown

    This looks very similar to the setup described at the Grokking Cocoa site. I’ve had logic test debugging working in earlier versions of Xcode, but now in Xcode 3.2.3, I inevitably get:

    Program loaded.
    run
    [Switching to process 19497]
    objc[19497]: found old-ABI metadata in image /usr/bin/arch !
    warning: The target crashed on startup, maybe the shell is crashing.
    “Try set start-with-shell 0″ to workaround.

    The Debugger has exited due to signal 6 (SIGABRT).The Debugger has exited due to signal 6 (SIGABRT).

    Any suggestions? Thanks very much!

  • AK

    Thank you for your post. It saved mea lot of frustration and time.

  • Matthew Phillips

    Thanks for taking the time to write this up, it’s been very helpful.

  • Vasudha

    Thanks this worked…
    Can you please help a bit more as I am unable to set breakpoints in my unit tests, please suggest for the same…
    Thanks in advanve

  • Pingback: Unit Testing in Xcode 4 – use OCUnit and SenTest instead of GHUnit | Long Weekend - iPhone & iPad Apps You'll Love!

  • Pingback: References on Unit Testing & UI Automation for iOS Applications | Jojit Soriano's Blog

  • http://www.mactonweb.com web design bangalore

    great post this very informative 

  • Janeltingson

    Fatastic! application, the “Love quotes” for iPhone.Where you can search
    and send “love quotes” for your loved ones.Visit us: http://itunes.apple.com/us/app/love-quotes-for-moods-love/id354968601?mt=8

  • Janeltingson

    Looking for “Love
    quotes”?The new application for iPhone and iPad is the right one for you! Visit
    us: http://itunes.apple.com/us/app/love-quotes-for-moods-love/id354968601?mt=8