Table of Contents
- Table of Contents
- Introduction
- Add the New Quality Gate (Build Breaker)
- Run the Maven Build – Failure
- Massage Errors Into Exclusions
- Protecting the Main Branches
- Summary
Introduction
Adding a quality gate, like unit test code coverage minimums, to a new (greenfield) project is easy. There are either no Java files, or very few Java files that may need new or updated unit tests to pass the new quality gate. However, an existing project may already contain thousands of lines of untested code. It may not be feasible to add unit tests to fill all of the existing gaps at the same time. However, this doesn’t mean that hope is lost. Instead, we just need to take a few extra steps.
Add the New Quality Gate (Build Breaker)
As described in the prior post: JaCoCo – Java Code Coverage, configure the new code coverage minimum quality gate(s).
To isolate the rules and their exclusions, let’s separate the limits each out into their own rule, so they can have their own exclusions. Let’s also add a place holder (excludes element set) to house the temporary exclusions.
<execution>
<id>check-ut</id>
<goals>
<!-- binds by default to the 'verify' Maven lifecycle phase -->
<goal>check</goal>
</goals>
<configuration>
<rules>
<!-- Build breaker rules to enforce in order to get a successful build -->
<rule>
<excludes>
<!-- Temporary exclusions to avoid breaking the build - INSTRUCTIONS -->
</excludes>
<!-- In each declared class. -->
<element>CLASS</element>
<limits>
<limit>
<!-- Individual instruction / command count (isn't impacted by formatting / line wrapping). -->
<counter>INSTRUCTION</counter>
<value>COVEREDRATIO</value>
<minimum>0.80</minimum>
</limit>
</limits>
</rule>
<!-- Build breaker rules to enforce in order to get a successful build -->
<rule>
<excludes>
<!-- Temporary exclusions to avoid breaking the build - BRANCHES -->
</excludes>
<!-- In each declared class. -->
<element>CLASS</element>
<limits>
<limit>
<!-- Branches of logic are things like individual true/false tests in an if / else / switch statement. -->
<counter>BRANCH</counter>
<value>COVEREDRATIO</value>
<minimum>0.80</minimum>
</limit>
</limits>
</rule>
</rules>
</configuration>
</execution>
Run the Maven Build – Failure
By running the Maven build now, we should see a build failure. To be sure that we don’t have any stale coverage information skewing the quality gate’s validation, we should include the clean goal along with our regular build command, such as:
mvn clean install
When the build fails, we need to capture the part of the output that indicates where the failure occurred, such as:
[WARNING] Rule violated for class codingchica.java101.App: instructions covered ratio is 0.00, but expected minimum is 0.80 [WARNING] Rule violated for class codingchica.java101.App: branches covered ratio is 0.00, but expected minimum is 0.80 [WARNING] Rule violated for class codingchica.java101.model.AgeUnits: instructions covered ratio is 0.00, but expected minimum is 0.80 [WARNING] Rule violated for class codingchica.java101.model.Animal: instructions covered ratio is 0.00, but expected minimum is 0.80 [WARNING] Rule violated for class codingchica.java101.model.Animal: branches covered ratio is 0.00, but expected minimum is 0.80
Massage Errors Into Exclusions
For each of the following, you can make these manipulations in IntelliJ IDE. Open a new Scratch file: Right click on Scratches and Consoles -> New -> Scratch File -> Plain text. Copy and paste the warning messages like those above into the new file. Edit Menu -> Find -> Replace. Select the Regular Expressions option (The button labelled with .*). For each search pattern and replacement, populate them in the first and second text boxes. Then, click Replace All.
Instructions Exclusions
Starting with a fresh copy of the warnings:
| Regular Expression Search Pattern | Replacement | Comments |
|---|---|---|
| ^.*branches.*$ | Remove branches lines, leaving only instructions lines. | |
| ^.*class | <exclude> | Replace everything before the class name with the starting exclude element. |
| :.* | </exclude> | Replace everything after the class name with the closing exclude element. |
| \n\n+ | \n | Remove blank lines |
Add Exclusions to Maven Build
Update the pom.xml just below the new <!– Temporary exclusions to avoid breaking the build – INSTRUCTIONS –> line with our massaged warning messages:
<configuration>
<rules>
<!-- Build breaker rules to enforce in order to get a successful build -->
<rule>
<excludes>
<!-- Temporary exclusions to avoid breaking the build - INSTRUCTIONS -->
<exclude>codingchica.java101.App</exclude>
<exclude>codingchica.java101.model.AgeUnits</exclude>
<exclude>codingchica.java101.model.Animal</exclude>
</excludes>
<!-- In each declared class. -->
<element>CLASS</element>
<limits>
<limit>
<!-- Individual instruction / command count (isn't impacted by formatting / line wrapping). -->
<counter>INSTRUCTION</counter>
<value>COVEREDRATIO</value>
<minimum>0.80</minimum>
</limit>
...
Branch Exclusions
Starting with a fresh copy of the warnings, paste them into our existing scratch file. For each search pattern and replacement, populate them in the first and second text boxes. Then, click Replace All.
| Regular Expression Search Pattern | Replacement | Comments |
|---|---|---|
| ^.*instructions.*$ | Remove instructions lines, leaving only branches lines. | |
| ^.*class | <exclude> | Replace everything before the class name with the starting exclude element. |
| :.* | </exclude> | Replace everything after the class name with the closing exclude element. |
| \n\n+ | \n | Remove blank lines |
Add Exclusions to Maven Build
Update the pom.xml just below the new <!– Temporary exclusions to avoid breaking the build – BRANCHES –> line with our massaged warning messages:
<!-- Build breaker rules to enforce in order to get a successful build -->
<rule>
<excludes>
<!-- Temporary exclusions to avoid breaking the build - BRANCHES -->
<exclude>codingchica.java101.App</exclude>
<exclude>codingchica.java101.model.Animal</exclude>
</excludes>
<!-- In each declared class. -->
<element>CLASS</element>
<limits>
<limit>
<!-- Branches of logic are things like individual true/false tests in an if / else / switch statement. -->
<counter>BRANCH</counter>
<value>COVEREDRATIO</value>
<minimum>0.80</minimum>
</limit>
</limits>
</rule>
Protecting the Main Branches
If working with a team, or on multiple branches/feature at once, be careful while introducing a new quality gate for any in-flight efforts.
- Add a Pull Request (PR) merge check to ensure that PR branches contain the latest from the main branch before merging,
- An automated build on the PR branch is successful before the branch is merged to the main branch(es)
- Alternatively, you might post a comment and task in any open PRs if the first two options are not available.
This way, we can protect the main branch(es) from needless build failures due to in-flight changes.
Summary
We have setup the code coverage quality gate to now enforce the code coverage minimums for new classes unit tests, while existing classes can temporarily be ignored until we have time to circle back and address the issues.
If you are able to, create ticket(s) to track the technical debt for these existing classes and the unit test gaps, then add comment(s) so that the ticket(s) can easily be found by other team members in the future.

Leave a comment