How to Debug Unit Test Bundles
I've realized that I've found a way to solve an incredibly persistent problem experienced by many.
Apple's unit test bundles can not be run from within Xcode with breakpoints set. If a test fails, this is fine, but if a test just plain blows up, how do you debug it? I've talked to a few local people and the answer seems to be, "You don't." Or, "Add lots of NSLog() messages." But here's a secret way to run the unit test bundle under gdb:
If you are developing for the Mac, this isn't a problem - it's in the path. If you are developing for iOS, we need to run in the simulator and use the gdb from the iOS SDK. You can use xcodebuild to find the correct one:
$ xcodebuild -sdk iphonesimulator4.2 -find gdb /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/gdb
otest is the program which runs a unit test bundle. You can use gdb's
-waitfor option to tell gdb to wait for the otest program to start.
$ $(xcodebuild -sdk iphonesimulator4.2 -find gdb) -waitfor otest GNU gdb 6.3.50-20050815 (Apple version gdb-1510) (Wed Sep 22 02:45:02 UTC 2010) Copyright 2004 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "x86_64-apple-darwin". Waiting for process 'otest' to launch.
Run your unit test bundle from Xcode. You will see gdb respond:
Attaching to process 45973. Reading symbols for shared libraries . done Reading symbols for shared libraries ................... done 0x8fe2dcfa in __dyld_mach_msg_trap () (gdb)
You are now attached to the process; however, your unit tests have not been loaded. If you simply need a stack trace from a SIGABRT, type "continue" and press enter, and you will stop at the fault with the ability to use "backtrace" to get a stack trace.
Otherwise, you can set a breakpoint on a particular line using
break Foo.m:151 or at a particular method using
break -[FooClass fooMethod]. Since your code isn't loaded yet, you will have to indicate that you want the break point set up when code is dynamically loaded. You can then use "continue" to continue until your breakpoint is hit.