Chapter 10Lesson 05~210 minutes

Checkpoint Lab — Maven Testing with Surefire, Failsafe, Integration Tests, Reports, and Quality Gates

Prove a Maven project has independently verifiable unit and integration suites, reproduce the misleading result caused by omitting Failsafe verify, and restore a trustworthy gate.

Checkpoint LabReport CountsFailure PropagationClean-RoomCI Evidence

Learning objectives

  • Build a project with independently visible Surefire and Failsafe suites.
  • Predict report/classpath/lifecycle changes before executing package and verify.
  • Capture test counts and report paths as CI-consumable evidence.
  • Demonstrate that omitting Failsafe verify creates a misleading green result.
  • Restore failure propagation and prove the correction from isolated state.
Current baseline — verified 2026-08-23. Labs use Maven 3.9.16 via Maven Wrapper 3.3.4, JDK 21 to run Maven, Java 17 as the compiler release target, JUnit 6.1.3, Surefire 3.5.6, Failsafe 3.5.6, Help Plugin 3.5.2, and Compiler Plugin 3.15.0. JUnit 6 requires Java 17 or newer. All Maven resolution uses a disposable project-local repository; no normal ~/.m2, global settings, production CI, or hosted quality platform is modified.
Cross-platform note: POSIX examples use ./mvnw, grep, find, and sha256sum. On Windows use mvnw.cmd, Select-String, Get-ChildItem, and Get-FileHash. Maven lifecycle semantics and report directories are cross-platform; shell quoting/path syntax are not.

1. Checkpoint acceptance contract

The checkpoint uses the same small production classes but turns the lesson into an evidence exercise. The finished project must prove all of the following without relying on an IDE:

Invariant Required evidence
One Surefire unit suite CalculatorTest report and nonzero expected count.
One Failsafe integration suite HealthServiceIT report plus failsafe-summary.xml.
Package is not the integration gate No Failsafe integration report is required before integration-test; explain lifecycle reach.
Verify is the integration gate Broken IT causes nonzero exit at Failsafe verify when configured correctly.
Broken configuration can mislead Same broken IT with Failsafe verify omitted demonstrates why execution alone is insufficient.
Clean-room proof Final run uses an isolated local repository and no normal user cache mutation.

2. Setup and preflight

Create a fresh disposable copy of the Lesson 2 project or rebuild it from the snippets. Preserve all command logs under evidence/; Maven clean removes target/, so evidence must live outside generated build output.

mkdir -p evidence
export LAB_REPO="$PWD/.lab-m2-checkpoint/repository"
./mvnw -v | tee evidence/toolchain.txt
./mvnw help:effective-pom -Doutput=evidence/effective-before.xml

3. Predict before execution

Prediction 1: clean package should execute Surefire and create target/surefire-reports, but the lifecycle has not yet reached Failsafe integration-test/verify.

Prediction 2: with the good POM, clean verify should create both report trees; replacing the IT expectation with DOWN should make the final Maven result nonzero at Failsafe verify.

Prediction 3: if failsafe:verify is removed while the broken IT remains, integration-test can record the failure without the normal Failsafe verification gate. That is the deliberately misleading state you must detect from reports rather than exit code alone.

4. Confirm the good POM and source identity

Use the Lesson 2 POM as the source of truth. Record a checksum before deliberately editing it so rollback is explicit.

sha256sum pom.xml src/main/java/dev/academy/testing/*.java src/test/java/dev/academy/testing/*.java | tee evidence/source-before.sha256
grep -n "maven-surefire-plugin\|maven-failsafe-plugin\|integration-test\|<goal>verify</goal>" pom.xml | tee evidence/plugin-bindings.txt

5. Prove package and verify are different gates

Run both from clean generated state. Preserve the logs outside target.

set -o pipefail
./mvnw -Dmaven.repo.local="$LAB_REPO" clean package | tee evidence/package.log
find target/surefire-reports -maxdepth 1 -type f -print | sort | tee evidence/package-surefire-files.txt
find target/failsafe-reports -maxdepth 1 -type f -print 2>/dev/null | sort | tee evidence/package-failsafe-files.txt || true
./mvnw -Dmaven.repo.local="$LAB_REPO" clean verify | tee evidence/verify-good.log
find target/surefire-reports target/failsafe-reports -maxdepth 1 -type f -print | sort | tee evidence/all-report-files.txt
grep -R "tests=\|failures=\|errors=" target/surefire-reports/TEST-*.xml target/failsafe-reports/TEST-*.xml | tee evidence/test-counts.txt

6. Inject an integration failure under the correct lifecycle

Back up HealthServiceIT.java, replace its expected value with DOWN, and run verify. Preserve the failure log and report before changing the POM.

cp src/test/java/dev/academy/testing/HealthServiceIT.java evidence/HealthServiceIT.good.java
sed -i.bak 's/assertEquals("UP"/assertEquals("DOWN"/' src/test/java/dev/academy/testing/HealthServiceIT.java
set +e
./mvnw -Dmaven.repo.local="$LAB_REPO" clean verify > evidence/correct-gate-failure.log 2>&1
correct_status=$?
set -e
printf 'correct verify exit=%s
' "$correct_status" | tee evidence/correct-gate-exit.txt
cp target/failsafe-reports/failsafe-summary.xml evidence/failsafe-summary-correct.xml 2>/dev/null || true
Required observation: the integration test runs, Failsafe records its failure, and the verify goal makes the Maven process fail. If the process exits 0, stop and inspect the effective POM before continuing.

7. Reproduce the misleading state: omit Failsafe verify

Save the good POM, then replace the Failsafe execution with the deliberately broken variant that contains integration-test but not verify. Keep the integration test broken. The goal is not to recommend this configuration; it is to prove why a test report and exit status must be interpreted together.

<plugin>
  <artifactId>maven-failsafe-plugin</artifactId>
  <version>3.5.6</version>
  <executions>
    <execution>
      <id>broken-it-only</id>
      <goals>
        <goal>integration-test</goal>
        <!-- verify intentionally omitted -->
      </goals>
    </execution>
  </executions>
</plugin>
cp pom.xml evidence/pom.good.xml
# edit only the Failsafe execution as shown above
set +e
./mvnw -Dmaven.repo.local="$LAB_REPO" clean verify > evidence/missing-verify.log 2>&1
broken_status=$?
set -e
printf 'missing-verify exit=%s
' "$broken_status" | tee evidence/missing-verify-exit.txt
find target/failsafe-reports -maxdepth 1 -type f -print | sort | tee evidence/missing-verify-report-files.txt
grep -R "failures=\|errors=" target/failsafe-reports/TEST-*.xml | tee evidence/missing-verify-counts.txt
Interpretation: if the integration report records a failure while the build is not rejected by Failsafe verify, you have demonstrated the exact false-green mechanism. The report is evidence that must not be ignored.

8. Restore the correct lifecycle and prove failure propagation

Restore the POM with both Failsafe goals. Keep the test broken for one more run and prove the build fails. Then restore the good test and prove the entire checkpoint becomes green.

cp evidence/pom.good.xml pom.xml
set +e
./mvnw -Dmaven.repo.local="$LAB_REPO" clean verify > evidence/repaired-still-broken.log 2>&1
repaired_status=$?
set -e
printf 'repaired broken-test exit=%s
' "$repaired_status" | tee evidence/repaired-exit.txt

cp evidence/HealthServiceIT.good.java src/test/java/dev/academy/testing/HealthServiceIT.java
./mvnw -Dmaven.repo.local="$LAB_REPO" clean verify | tee evidence/final-green.log
sha256sum target/*.jar | tee evidence/final-artifact.sha256

9. Verification checklist

Question Evidence
Did the unit suite run? Surefire XML/text + test count.
Did the integration suite run? Failsafe XML/text + summary.
Did package and verify differ as predicted? Preserved package/verify report file lists.
Did correct configuration reject the broken IT? correct-gate-exit.txt and Failsafe failure report.
Did missing verify demonstrate misleading failure semantics? missing-verify-exit.txt plus failing integration report.
Did restoration reject the broken test, then pass the good test? repaired-exit.txt and final-green.log.
Were normal user caches untouched? All Maven downloads used $LAB_REPO.

10. Cleanup / rollback

Ensure the good POM and good integration test are restored. Keep evidence/ if you want the checkpoint record, or remove the entire disposable project. Delete only .lab-m2-checkpoint if reclaiming lab disk space. Do not mutate normal user Maven state.

Knowledge check

Why preserve evidence outside target/?

Why can a failing Failsafe integration report coexist with a misleading successful process when verify is omitted?

What proves a test gate more strongly than exit code alone?

Why restore verify before restoring the broken test?

Which Maven phase should a protected CI job normally invoke when Failsafe integration tests are required?

What production capability does Chapter 10 add?

11. Production operating model and Chapter 11 bridge

Chapter 10 adds a reliable quality-evidence boundary to the build system. Teams can now prove not merely that Maven exited successfully, but that the intended suites ran at the intended lifecycle stages, generated inspectable reports, and failed the delivery gate correctly. Chapter 11 builds on that evidence contract with Maven dependencyManagement, BOM imports, version alignment, Enforcer rules, and dependency analysis across modules.

Official references and version notes

Version-sensitive statements were checked against Apache Maven and JUnit primary documentation on 2026-08-23. The mandatory path pins Maven 3.9.16 via Maven Wrapper 3.3.4, JDK 21 to run Maven, Java 17 as the release target, JUnit 6.1.3, Maven Surefire Plugin 3.5.6, Maven Failsafe Plugin 3.5.6, Help Plugin 3.5.2, and Compiler Plugin 3.15.0.

Apache's current Surefire site advertises 3.6.0-M1. Because the version itself is a milestone identifier, these lessons treat it as version-sensitive preview/milestone material and keep the hands-on path on the final 3.5.6 line. Re-check before adopting a newer line in production.

The checkpoint intentionally keeps the integration failure harmless and local. No external service or paid test platform is required.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.