C/C++ Code Coverage Testing
Created:
2018-05-14
Updated:
2018-05-14
Coverage testing measures the effectiveness of test suites by determining the code coverage. It identifies areas of the code that haven’t been executed, enabling to improve test quality and enhance software reliability.
Coverage information files
To build object files capable to produce coverage data the gcc
coverage
option should be used.
Compilation:
$ gcc --coverage -c test.c
Linking
$ gcc --coverage test.o -o test
The --coverage
option is used to compile and link code instrumented for
coverage analysis and is synonym for -fprofile-arcs -ftest-coverage
(when
compiling) and -lgcov
(when linking).
When compiling, this switch produces, along with the object file, a .gcno
file
containing the information to reconstruct the basic block graphs and assign
source line numbers to blocks. This file is the product of the -ftest-coverage
compiler switch.
When executing a file compiled/linked with the coverage
options a gcda
file
containing the effective program flow recordings is produced. This file is the
product of the -fprofile-arcs
switch.
Excerpt from the gcc
online manual:
-fprofile-arcs
Add code so that program flow arcs are instrumented. During execution
the program records how many times each branch and call is executed and
how many times it is taken or returns.
When the compiled program exits it saves this data to a file called
auxname.gcda for each source file. The data may be used for
profile-directed optimizations (-fbranch-probabilities), or for test
coverage analysis (-ftest-coverage). Each object file’s auxname is
generated from the name of the output file, if explicitly specified and
it is not the final executable, otherwise it is the basename of the
source file. In both cases any suffix is removed (e.g. foo.gcda for
input file dir/foo.c, or dir/foo.gcda for output file specified as -o
dir/foo.o).
-ftest-coverage
Produce a notes file that the gcov code-coverage utility (see gcov—a
Test Coverage Program) can use to show program coverage. Each source
file’s note file is called auxname.gcno. Refer to the -fprofile-arcs
option above for a description of auxname and instructions on how to
generate test coverage data. Coverage data matches the source files
more closely if you do not optimize.
GCOV
GCOV is a GNU tool which provides information about what parts of a program are actually executed (i.e. “covered”) while running a particular test case.
This tool usually comes bundled with the GCC toolchain.
Assuming that we’ve compiled and linked a source file with the gcc
--coverage
switch, a specific source file coverage report is generated with
the following command:
$ gcov test.o
The command will automatically use the test.gcda
and test.gcno
files in the
directory of the analyzed file to generate a test.c.gcov
file and to print
coverage stats to the stdout.
The .gcov
file is a human-readable file and contains the analyzed file sources
plus coverage information (i.e. if a line has been covered and for how many
times).
NOTE
If we run the executable multiple times then the new execution coverage
information is appended to the previous gcda
file. This allows coverage
statistics when the execution path is not systematically the same (e.g. this
may happen if the malloc
is involved).
LCOV
LCOV is an extension of GCOV, The extension consists of a set of Perl scripts which build on the textual GCOV output to implement the following enhanced functionality:
- HTML based output: coverage rates are additionally indicated using bar graphs and specific colors.
- Support for large projects: overview pages allow quick browsing of coverage data by providing three levels of detail: directory view, file view and source code view.
Basic usage
The most straightforward way to use LCOV is to first run it to zero all the
counters (i.e. delete the gcda
files)
$ lcov -z -d <gcda-files-dir>
Next run the executable compiled to produce gcda
files (i.e. the same run
for lcov
).
$ lcov -c -d <gcda-files-dir> -o cover.info
LCOV will produce coverage information only for the program object files that
has an associated gcda
file. That is, object files that were linked to the
final executable.
To produce coverage information for all the object files, that were
compiled with the --coverage
switch, even if they were not linked to the
program we must use the -i
option (capture initial zero coverage data).
The flag will generate coverage information (with zero coverage) for every
object file having an associated gcno
file.
First clean up gcda
files
$ lcov -z -d <gcda-files-dir>
Run the executable to produce the gcda
files.
Scan for gcno
file to produce coverage for all the object files within the
project (even if are not linked).
$ lcov -c -i -d <gcda-files-dir> -o base.info
Generate effective coverage data as usual and save it in a different info file.
$ lcov -c -d <gcda-files-dir> -o cover.info
Merge the two files into a single, complete, coverage file
$ lcov -a base.info -a cover.info -o allcover.info
HTML generation
The info
files alone are not meant for human consumption.
You can generate a nice HTML version of the coverage data by using the
genhtml
tool
$ genhtml cover.info [-o outdir]
GCOVR
Inspired by the Python coverage.py
package, the GCOVR command provides a
utility for running the GCOV tool and summarizing code coverage results.
Further, GCOVR can be viewed as a command-line alternative of the LCOV utility, which runs GCOV and generates an HTML output.
The gcovr
command can produce different kinds of coverage reports:
- default: compact human-readable summaries
--xml
: machine-readable XML reports in Cobertura format--html
: HTML summaries--html-details
: HTML report with annotated source files
Usage is pretty similar to the other tools.
If you want to quickly display a concise coverage report on the command line,
GCOVR is the ideal tool since you can issue the command on the project root
without issuing it against every file like direct usage of GCOV (without
recurring to xargs
).
COVERALLS
If your project is versioned by git
and hosted on github.com
then
coveralls.io
offers a free nice view of coverage data.
Inspired from python-coveralls
, it uploads the coverage report of C/C++
project to coveralls.io
.
Installation
$ pip install cpp-coveralls
Quick usage:
- build the project with coverage support (as usual)
- Run the tests
- Run coveralls
Popular run options
$ coveralls -b . --exclude <test-dir> --gcov-options '\-lp'
To be published to the coveralls.io
website, the above commands can be run
from a docker
image started by the Travis CI service.