Heart containing Coding Chica Java 101

Adding JaCoCo Quality Gate to an existing code base

Table of Contents

  1. Table of Contents
  2. Introduction
  3. Add the New Quality Gate (Build Breaker)
  4. Run the Maven Build – Failure
  5. Massage Errors Into Exclusions
    1. Instructions Exclusions
      1. Add Exclusions to Maven Build
    2. Branch Exclusions
      1. Add Exclusions to Maven Build
  6. Protecting the Main Branches
  7. 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 PatternReplacementComments
^.*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+\nRemove 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 PatternReplacementComments
^.*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+\nRemove 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.

Adding JaCoCo Quality Gate to an existing code base

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.