Blog

Unit testing and coverage with XCode

There are several great resources out there on how to incorporate unit testing into XCode projects. It’s all built into XCode now, and it’s fantastic.

I just got coverage working too, thanks to a useful article at SuperMegaUltraGroovy on how to use code coverage with XCode. There were a couple of caveats that I thought I’d share, though.So, to repeat SMUG’s instructions:

  1. Set up unit testing
  2. Create a new build configuration (‘Coverage’), duplicated from the ‘Debug’ configuration
  3. Open up build settings for the main target, make sure your new configuration is selected, and:
    • Enable “Generate Test Coverage Files”
    • Enable “Instrument Program Flow”
    • Add “-lgcov” to “Other Linker Flags”

SMUG proposes some commands to append to the “Run Script” build phase of the unit test target, in order to generate the coverage report and output a summary to the build results (see the original article). I made some modifications to aid readability. So, instead, I added the following to the “Run Script” phase of the unit test target:

# Run gcov on the framework getting tested
if [ "${CONFIGURATION}" = 'Coverage' ]; then
     TARGET_NAME="My Application"
     OBJ_DIR=${OBJROOT}/${TARGET_NAME}.build/${CONFIGURATION}/${TARGET_NAME}.build/Objects-normal/${CURRENT_ARCH}
     mkdir -p Coverage
     pushd Coverage
     find "${OBJROOT}" -name *.gcda -exec gcov -o "${OBJ_DIR}" {} \; 2>/tmp/gconv-stderr | egrep "^File|^Lines" | sed -E "s@File '$SRCROOT/@@;s@(\.[a-zA-Z])'@\1: @;s@Lines executed:([0-9.%]+) of ([0-9]+)@\1 (\2)@" | paste -d" " - - | egrep -v "^File '" | sed -E "s@^([^:]+):([^(]*)(\([^)]+\))@\2:\1\3@" | sort -n | sed -E "s@^([^:]+):([^(]*)(\([^)]+\))@\2:\1\3@"; cat /tmp/gconv-stderr | grep -v "version.*, prefer.*"; rm /tmp/gconv-stderr
     popd
fi

This orders the results by coverage percentage, reformats the output to be a bit terser and more readable, and suppresses some unnecessary warnings about GCC 4.0 (see below).

Finally, using XCode 3.2 on Snow Leopard (Mac OS X 10.6), I found that there were a few issues. Using any SDK other than 10.6 results in build errors:

vproc_transaction_begin”, referenced from:
__gcov_init in libgcov.a(_gcov.o)
_vproc_transaction_begin$non_lazy_ptr in libgcov.a(_gcov.o)
“_vproc_transaction_end”, referenced from:
_gcov_exit in libgcov.a(_gcov.o)
_vproc_transaction_end$non_lazy_ptr in libgcov.a(_gcov.o)
ld: symbol(s) not found

The solution I found in the Apple lists archives is to use the same SDK as the OS: 10.6 (Project menu, Set Active SDK, 10.6).

After fixing this, I was getting dubious-looking results – mostly 0.00% code coverage except for a few random files. The suggestion for this was to use GCC 4.0 instead of the default 4.2 (edit build settings for the main target, and probably the unit test target too, and select “GCC 4.0″ under “C/C++ Compiler Version”).

After a clean and rebuild, I’m getting proper results.

Phew.

Tagged , , . Bookmark the permalink. Both comments and trackbacks are currently closed.

One Comment

  1. anilkumar
    Posted January 21, 2010 at 10:10 am | Permalink

    How to resolve undefined reference to `stderr’ , while building code with -lgcov and -fprofile-arcs and -ftest-coverage flags in Centos