Tier 4 │ *IntegrationTest.java │ Testcontainers + @SpringBootTest + RestAssured │ mvn verify
Tier 3 │ Security slice tests │ @SpringBootTest (mocked DB) + RestAssured │ mvn verify
Tier 2 │ Spring wiring tests │ @ContextConfiguration (no HTTP, no DB) │ mvn test
Tier 1 │ *Test.java │ Mockito unit tests │ mvn test
# Tier 1 + 2: unit tests only (no Docker required, under 60s)
./mvnw clean test
# Tier 3 + 4: full pipeline including integration tests (Docker required)
./mvnw clean verify
# Run a single integration test class
./mvnw verify -Dit.test=SelfServiceAuthenticationIntegrationTest
# Skip spotless formatting check (useful during local development)
./mvnw verify -Dspotless.check.skip=trueJaCoCo measures both unit and integration test coverage and merges them before enforcing thresholds.
| Metric | Measured Baseline | Enforced Floor | Goal |
|---|---|---|---|
| Line | 54.60% | 54% | +5%/sprint |
| Method | 56.74% | 56% | +5%/sprint |
| Branch | 10.46% | 10% | +5%/sprint |
Coverage reports are written to:
target/site/jacoco/— unit tests onlytarget/site/jacoco-merged/— unit + integration (this is what the CI gate checks)
- Create your test file with the
*IntegrationTest.javasuffix. - Extend
SelfServiceIntegrationTestBase. - Inject
@LocalServerPort int portand useSelfServiceTestUtils.requestSpec(port)for RestAssured calls.
class MyFeatureIntegrationTest extends SelfServiceIntegrationTestBase {
@Test
void myEndpoint_withNoAuth_returns401() {
given(SelfServiceTestUtils.requestSpec(port))
.when().get("/api/v1/self/my-endpoint")
.then().statusCode(401);
}
}| Suffix | Picked up by | Phase |
|---|---|---|
*Test.java |
Surefire | test |
*IntegrationTest.java |
Failsafe | verify |
Three sequential GitHub Actions jobs:
- Unit Tests — runs
mvn test, uploadsjacoco.exec - Integration Tests — runs
mvn verify -Dsurefire.skip=true, uploadsjacoco-it.exec - Coverage Gate — downloads both exec files, merges them, enforces thresholds
Both jobs run on every push and every pull request against develop.