With the help of
GitLab CI/CD
, you can collect the test
coverage information of your favorite testing or coverage-analysis tool, and visualize
this information inside the file diff view of your merge requests (MRs). This allows you
to see which lines are covered by tests, and which lines still require coverage, before the
MR is merged.
How test coverage visualization works
Collecting the coverage information is done via GitLab CI/CD’s
artifacts reports feature
.
You can specify one or more coverage reports to collect, including wildcard paths.
GitLab then takes the coverage information in all the files and combines it
together. Coverage files are parsed in a background job so there can be a delay
between pipeline completion and the visualization loading on the page.
For the coverage analysis to work, you have to provide a properly formatted
Cobertura XML
report to
artifacts:reports:coverage_report
.
This format was originally developed for Java, but most coverage analysis frameworks
for other languages have plugins to add support for it, like:
Once configured, if you create a merge request that triggers a pipeline which collects
coverage reports, the coverage is shown in the diff view. This includes reports
from any job in any stage in the pipeline. The coverage displays for each line:
covered
(green): lines which have been checked at least once by tests
no test coverage
(orange): lines which are loaded but never executed
no coverage information: lines which are non-instrumented or not loaded
Hovering over the coverage bar provides further information, such as the number
of times the line was checked by tests.
The visualization only displays after the pipeline is complete. If the pipeline has
a
blocking manual job
, the
pipeline waits for the manual job before continuing and is not considered complete.
The visualization cannot be displayed if the blocking manual job did not run.
The coverage report properly matches changed files only if the
filename
of a
class
element
contains the full path relative to the project root. However, in some coverage analysis frameworks,
the generated Cobertura XML has the
filename
path relative to the class package directory instead.
To make an intelligent guess on the project root relative
class
path, the Cobertura XML parser
attempts to build the full path by:
Extracting a portion of the
source
paths from the
sources
element and combining them with the
class
filename
path.
Checking if the candidate path exists in the project.
Using the first candidate that matches as the class full path.
GitLab expects the artifact in the Cobertura format, so you have to execute a few
scripts before uploading it. The test-jdk11 job tests the code and generates an
XML artifact. The coverage-jdk-11 job converts the artifact into a Cobertura report:
test-jdk11:stage:testimage:maven:3.6.3-jdk-11script:-mvn $MAVEN_CLI_OPTS clean org.jacoco:jacoco-maven-plugin:prepare-agent test jacoco:reportartifacts:paths:-target/site/jacoco/jacoco.xmlcoverage-jdk11:# Must be in a stage later than test-jdk11's stage.# The `visualize` stage does not exist by default.# Please define it first, or choose an existing stage like `deploy`.stage:visualizeimage:registry.gitlab.com/haynes/jacoco2cobertura:1.0.7script:# convert report from jacoco to cobertura, using relative project path-python /opt/cover2cover.py target/site/jacoco/jacoco.xml $CI_PROJECT_DIR/src/main/java/ > target/site/cobertura.xmlneeds:["test-jdk11"]artifacts:reports:coverage_report:coverage_format:coberturapath:target/site/cobertura.xml
GitLab expects the artifact in the Cobertura format, so you have to execute a few
scripts before uploading it. The test-jdk11 job tests the code and generates an
XML artifact. The coverage-jdk-11 job converts the artifact into a Cobertura report:
test-jdk11:stage:testimage:gradle:6.6.1-jdk11script:-'gradletestjacocoTestReport'# jacoco must be configured to create an xml reportartifacts:paths:-build/jacoco/jacoco.xmlcoverage-jdk11:# Must be in a stage later than test-jdk11's stage.# The `visualize` stage does not exist by default.# Please define it first, or chose an existing stage like `deploy`.stage:visualizeimage:registry.gitlab.com/haynes/jacoco2cobertura:1.0.7script:# convert report from jacoco to cobertura, using relative project path-python /opt/cover2cover.py build/jacoco/jacoco.xml $CI_PROJECT_DIR/src/main/java/ > build/cobertura.xmlneeds:["test-jdk11"]artifacts:reports:coverage_report:coverage_format:coberturapath:build/cobertura.xml
Python example
The following .gitlab-ci.yml example for Python uses pytest-cov to collect test coverage data and coverage.py to convert the report to use full relative paths.
The information isn’t displayed without the conversion.
This example assumes that the code for your package is in src/ and your tests are in tests.py:
run tests:stage:testimage:python:3script:-pip install pytest pytest-cov-coverage run -m pytest-coverage report-coverage xmlcoverage:'/(?i)total.*?(100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/'artifacts:reports:coverage_report:coverage_format:coberturapath:coverage.xml
Codeception, through PHPUnit, also supports generating Cobertura report with
run. The path for the generated file
depends on the --coverage-cobertura option and paths
configuration for the unit test suite. Configure .gitlab-ci.yml
to find Cobertura in the appropriate path.
C/C++ example
The following .gitlab-ci.yml example for C/C++ with
gcc or g++ as the compiler uses gcovr to generate the coverage
output file in Cobertura XML format.
This example assumes:
That the Makefile is created by cmake in the build directory,
within another job in a previous stage.
(If you use automake to generate the Makefile,
then you need to call make check instead of make test.)
cmake (or automake) has set the compiler option --coverage.
gocover-cobertura to convert Go’s coverage profile into the Cobertura XML format.
This example assumes that Go modules
are being used. The -covermode count option does not work with the -race flag.
If you want to generate code coverage while also using the -race flag, you must switch to
-covermode atomic which is slower than -covermode count. See this blog post
for more details.
run tests:stage:testimage:golang:1.17script:-go install-go test ./... -coverprofile=coverage.txt -covermode count-go get github.com/boumenot/gocover-cobertura-go run github.com/boumenot/gocover-cobertura < coverage.txt > coverage.xmlartifacts:reports:coverage_report:coverage_format:coberturapath:coverage.xml
simplecov and simplecov-cobertura
to record the coverage profile and create a report in the Cobertura XML format.
This example assumes:
That bundler is being used for dependency management.
The rspec, simplecov and simplecov-cobertura gems have been added to your Gemfile.
The CoberturaFormatter has been added to your SimpleCov.formatters
configuration within the spec_helper.rb file.
run tests:stage:testimage:ruby:3.1script:-bundle install-bundle exec rspecartifacts:reports:coverage_report:coverage_format:coberturapath:coverage/coverage.xml
Report artifacts are not downloadable by default. If you want the report to be downloadable
from the job details page, add your coverage report to the artifact paths:
View pricing
to see all GitLab tiers and features, or to upgrade. Try GitLab for free
with access to all features for 30 days.
Get Help
If you didn't find what you were looking for,
search the docs.
If you want help with something specific and could use community support,
post on the GitLab forum.
For problems setting up or using this feature (depending on your GitLab
subscription).