As we all know, unit test has been a crucial part of software development. I feel I was walking on ice if I was coding without writing tests. But even if we have unit tests, things may still go wrong if the tests have bad coverage. Fortunately, there are many tools today to help us analyze our code and give us every detail of the quality of our unit tests. GNU gcov is such a tool for code compiled with GCC.
gcov is very easy to use. If you’re developing a C/C++ project, all you have to do is to compile your project with “-g -O0 –coverage”. “–coverage” is a synonym for-fprofile-arcs, -ftest-coverage(compiling) and-lgcov(linking). This tells the compiler to generate additional information and code needed by gcov.
OK, let’s run our tests. GCC will generate a bunch of files(profiles) that will be used later. These files know how your tests was executed and record many information such as arc transition counts and some summary information. Now we’re ready to view our test coverage now with gcov. But gcov doesn’t give us a report that is easy to read and it’s not convenient. Here comes the tool called “LCOV”.
LCOV is a graphical front-end for gcov. It collects gcov data for multiple source files and creates HTML pages containing the source code annotated with coverage information. It also adds overview pages for easy navigation within the file structure. LCOV supports statement, function and branch coverage measurement. The above picture is a test coverage report generated by LCOV.
LCOV is quite easy to use too so you can refer to its man page for its usage. In our libbash project, I wrote a script to generate test coverage report. It creates a completely new environment based on “make dist” so you don’t have to change any GCC flag at all. Note that libtool doesn’t work well with gcov so you have to use static linking for all your libraries(–disable-shared). The reason is libtool uses -nostdlib to compile the libraries. I’ve already reported this issue to libtool mail list but haven’t got anything helpful yet.
Feel free to modify to fit your needs.
#!/bin/sh
which lcov 1>/dev/null 2>&1
if [ $? != 0 ]
then
echo "You need to have lcov installed in order to generate the test coverage report"
exit 1
fi
if [ ! $DIST_ARCHIVES ]
then
echo "You need to provide the archive name by running DIST_ARCHIVES=\"ARCHIVE_NAME\" $0"
exit 1
fi
tar zxf $DIST_ARCHIVES
srcdir=${DIST_ARCHIVES/.tar.gz}
cd $srcdir
# Reconfigure with gcov support
CXXFLAGS="-g -O0 --coverage" CFLAGS="-g -O0 --coverage" ./autogen.sh --disable-shared
# Generate gcov output
${MAKE}
# Generate html report
lcov --base-directory . --directory . --zerocounters -q
${MAKE} check
lcov --base-directory . --directory . -c -o libbash_test.info
lcov --remove libbash_test.info "/usr*" -o libbash_test.info # remove output for external libraries
rm -rf ../test_coverage
genhtml -o ../test_coverage -t "libbash test coverage" --num-spaces 4 libbash_test.info
# Clean work space
cd .. && rm -rf $srcdir

