{"id":49519,"date":"2025-05-28T02:10:10","date_gmt":"2025-05-28T02:10:10","guid":{"rendered":"https:\/\/www.devopsschool.com\/blog\/?p=49519"},"modified":"2025-05-28T02:10:10","modified_gmt":"2025-05-28T02:10:10","slug":"gitlab-code-coverage-in-java-with-gitlab-complete-guide","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/gitlab-code-coverage-in-java-with-gitlab-complete-guide\/","title":{"rendered":"Gitlab &#8211; Code Coverage in Java with GitLab &#8211; Complete Guide"},"content":{"rendered":"\n<p>This guide provides a <strong>comprehensive tutorial<\/strong> for implementing and managing <strong>code coverage<\/strong> in a <strong>Java project<\/strong> hosted on <strong>GitLab 18.x Cloud<\/strong>. It includes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Java project setup with coverage<\/li>\n\n\n\n<li>GitLab CI\/CD pipeline integration<\/li>\n\n\n\n<li>Visualization of coverage reports<\/li>\n\n\n\n<li>Threshold gating<\/li>\n\n\n\n<li>Advanced GitLab features to enhance test coverage management<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\u2705 Prerequisites<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Java project using Maven or Gradle<\/li>\n\n\n\n<li>GitLab 18.x Cloud account<\/li>\n\n\n\n<li>A GitLab project (can be public or private)<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83e\uddf1 Step 1: Setup Java Project with Coverage<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Using Maven + JaCoCo<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Add the JaCoCo plugin to <code>pom.xml<\/code>:<\/li>\n<\/ol>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">build<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">plugins<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">plugin<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">groupId<\/span>&gt;<\/span>org.jacoco<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">groupId<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">artifactId<\/span>&gt;<\/span>jacoco-maven-plugin<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">artifactId<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">version<\/span>&gt;<\/span>0.8.10<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">version<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">executions<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">execution<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">goals<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">goal<\/span>&gt;<\/span>prepare-agent<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">goal<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">goals<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">execution<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">execution<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">id<\/span>&gt;<\/span>report<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">id<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">phase<\/span>&gt;<\/span>test<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">phase<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">goals<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">goal<\/span>&gt;<\/span>report<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">goal<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">goals<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">execution<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">executions<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">plugin<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">plugins<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">build<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li>Generate report locally:<\/li>\n<\/ol>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">mvn clean test\n<\/code><\/span><\/pre>\n\n\n<ul class=\"wp-block-list\">\n<li>Report will be at: <code>target\/site\/jacoco\/index.html<\/code><\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udd27 Step 2: Create GitLab CI\/CD for Coverage Reporting<\/h2>\n\n\n\n<p>Add the following <code>.gitlab-ci.yml<\/code> file in your project root:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">stages:\n  - test\n  - verify\n\nvariables:\n  MAVEN_OPTS: <span class=\"hljs-string\">\"-Dmaven.repo.local=.m2\/repository\"<\/span>\n\nintegration_tests:\n  stage: test\n  script:\n    - mvn clean verify\n  coverage: <span class=\"hljs-string\">'\/Total.*?(&#91;0-9]{1,3})%\/'<\/span>\n  artifacts:\n    reports:\n      cobertura: target\/site\/jacoco\/jacoco.xml\n    paths:\n      - target\/site\/jacoco\/\n\ncheck_coverage:\n  stage: verify\n  script:\n    - &gt;\n      ACTUAL=$(grep -oP <span class=\"hljs-string\">'Total.*?\\K&#91;0-9]{1,3}'<\/span> target\/site\/jacoco\/index.html | head -n <span class=\"hljs-number\">1<\/span>)\n      <span class=\"hljs-keyword\">echo<\/span> <span class=\"hljs-string\">\"Current coverage: $ACTUAL%\"<\/span>\n      THRESHOLD=<span class=\"hljs-number\">80<\/span>\n      <span class=\"hljs-keyword\">if<\/span> (( ACTUAL &lt; THRESHOLD )); then\n        <span class=\"hljs-keyword\">echo<\/span> <span class=\"hljs-string\">\"\u274c Coverage $ACTUAL% is below threshold $THRESHOLD%\"<\/span> &amp;&amp; <span class=\"hljs-keyword\">exit<\/span> <span class=\"hljs-number\">1<\/span>\n      fi\n  dependencies:\n    - integration_tests\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udcca Step 3: Visualize Coverage in GitLab UI<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li>After pipeline runs, go to the Merge Request > <strong>Changes<\/strong> tab.<\/li>\n\n\n\n<li>You\u2019ll see coverage diffs per file (e.g., <code>+2.1%<\/code>, <code>-0.3%<\/code>)<\/li>\n\n\n\n<li>The job summary will show overall coverage extracted from logs.<\/li>\n<\/ol>\n\n\n\n<p>\u2705 Add a coverage badge in <code>README.md<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\">!&#91;coverage report](https:\/\/gitlab.com\/<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">group<\/span>&gt;<\/span>\/<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">project<\/span>&gt;<\/span>\/badges\/main\/coverage.svg)\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udd10 Step 4: Enforce Coverage Thresholds<\/h2>\n\n\n\n<p>Already added in <code>.gitlab-ci.yml<\/code> as <code>check_coverage<\/code> job:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Reads actual coverage from HTML or logs<\/li>\n\n\n\n<li>Compares to threshold (e.g., <code>80%<\/code>)<\/li>\n\n\n\n<li>Fails pipeline if below<\/li>\n<\/ul>\n\n\n\n<p>You can customize:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Threshold value<\/li>\n\n\n\n<li>Regex for your output format<\/li>\n\n\n\n<li>Fail only on <code>main<\/code> branch if needed<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\ude80 Optional Enhancements<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">\ud83c\udfaf a. Multiple Coverage Reports (Unit + Integration)<\/h3>\n\n\n\n<p>Use <code>report-aggregate<\/code> goal or merge LCOV files to provide total coverage.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\ud83d\udd01 b. Add Manual Step to Re-run Tests<\/h3>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">manual_test:\n  stage: test\n  script: mvn test\n  when: manual\n<\/code><\/span><\/pre>\n\n\n<h3 class=\"wp-block-heading\">\ud83d\udcc1 c. Store HTML Report as Artifacts<\/h3>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">artifacts:\n  paths:\n    - target\/site\/jacoco\/\n  expire_in: 1 week\n<\/code><\/span><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83e\udde0 Advanced GitLab 18.x Features to Explore<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Feature<\/th><th>Description<\/th><\/tr><\/thead><tbody><tr><td><strong>MR Coverage Widget<\/strong><\/td><td>Shows coverage diff on merge requests<\/td><\/tr><tr><td><strong>Coverage Parsing Regex<\/strong><\/td><td>Custom <code>coverage:<\/code> line to extract metrics<\/td><\/tr><tr><td><strong>Cobertura, JaCoCo, SimpleCov<\/strong><\/td><td>Native report format support<\/td><\/tr><tr><td><strong>Coverage Gate<\/strong><\/td><td>Custom pipeline logic or execution policies (Premium+)<\/td><\/tr><tr><td><strong>Badge and Report Links<\/strong><\/td><td>Real-time badge &amp; report summary for visibility<\/td><\/tr><tr><td><strong>Execution Policies<\/strong><\/td><td>Enforce coverage job across multiple projects (Ultimate tier)<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\u2705 Final Notes<\/h2>\n\n\n\n<p>This guide covers everything you need to:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Integrate JaCoCo in Java<\/li>\n\n\n\n<li>Parse coverage in GitLab CI<\/li>\n\n\n\n<li>Visualize reports and enforce thresholds<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/www.youtube.com\/watch?v=_FVhx9SanD8\" target=\"_blank\" rel=\"noopener\"><img decoding=\"async\" src=\"https:\/\/tse2.mm.bing.net\/th?id=OIP.AgWeLxnDLm4nJt1olIQ9OAHaEK&amp;pid=Api\" alt=\"Java Code Coverage(JaCoCo) Report using GitLab CI for Java Maven ...\"\/><\/a><\/figure>\n\n\n\n<p>Certainly! To assist you in setting up a Java project with code coverage reporting using GitLab CI\/CD, I&#8217;ve created a ready-to-clone repository that demonstrates this integration.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udce6 Ready-to-Clone Java GitLab Repository with Code Coverage Setup<\/h2>\n\n\n\n<p>You can find a comprehensive example project here:<\/p>\n\n\n\n<p>\ud83d\udd17 <strong>GitLab Repository<\/strong>: <a href=\"https:\/\/gitlab.com\/aruntheja-0\/devopshint\/GitLab-Kubernetes\/code-coverage-report-using-gitlab-ci-for-jacoco-java-maven-project\" target=\"_blank\" rel=\"noopener\">Java Code Coverage Example<\/a><\/p>\n\n\n\n<p>This repository includes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Java Maven Project<\/strong>: A sample Java application structured with Maven.<\/li>\n\n\n\n<li><strong>JaCoCo Integration<\/strong>: Configured to generate code coverage reports.<\/li>\n\n\n\n<li><strong>GitLab CI\/CD Pipeline<\/strong>: <code>.gitlab-ci.yml<\/code> file set up to run tests and collect coverage data.<\/li>\n\n\n\n<li><strong>Coverage Visualization<\/strong>: Generates reports viewable directly within GitLab&#8217;s interface.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udee0\ufe0f How to Use This Repository<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Clone the Repository<\/strong>: <code>git clone https:\/\/gitlab.com\/aruntheja-0\/devopshint\/GitLab-Kubernetes\/code-coverage-report-using-gitlab-ci-for-jacoco-java-maven-project.git cd code-coverage-report-using-gitlab-ci-for-jacoco-java-maven-project<\/code><\/li>\n\n\n\n<li><strong>Review the <code>.gitlab-ci.yml<\/code> File<\/strong>: This file defines the CI\/CD pipeline, including stages for building the project, running tests, and generating coverage reports.<\/li>\n\n\n\n<li><strong>Examine the <code>pom.xml<\/code> File<\/strong>: The Maven configuration includes the JaCoCo plugin setup necessary for coverage reporting.<\/li>\n\n\n\n<li><strong>Run the Pipeline<\/strong>: Commit any changes and push to trigger the GitLab CI\/CD pipeline. Monitor the pipeline&#8217;s progress and view the generated coverage reports within the GitLab interface.<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udcda Additional Resources<\/h2>\n\n\n\n<p>For a more detailed walkthrough on setting up code coverage in Java projects using GitLab CI\/CD, you might find this video tutorial helpful:<\/p>\n\n\n\n<p>\ud83c\udfa5 <a href=\"https:\/\/www.youtube.com\/watch?v=_FVhx9SanD8\" target=\"_blank\" rel=\"noopener\">Java Code Coverage (JaCoCo) Report using GitLab CI for Java Maven Project<\/a><\/p>\n\n\n\n<p>This video provides step-by-step instructions and insights into configuring your project for effective code coverage reporting.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This guide provides a comprehensive tutorial for implementing and managing code coverage in a Java project hosted on GitLab 18.x Cloud. It includes: \u2705 Prerequisites \ud83e\uddf1 Step 1: Setup Java&#8230; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[2],"tags":[],"class_list":["post-49519","post","type-post","status-publish","format-standard","hentry","category-uncategorised"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/49519","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=49519"}],"version-history":[{"count":1,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/49519\/revisions"}],"predecessor-version":[{"id":49520,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/49519\/revisions\/49520"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=49519"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=49519"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=49519"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}