This convention applies to Maven-based Java services in the Digital Bank Java platform.
- Keep fast feedback fast.
- Separate pure unit tests from Spring, HTTP, database, and container-backed integration tests.
- Make local commands and CI stages predictable across services.
- Keep future quality gates easy to add without changing every service differently.
| Type | Purpose | Typical tools | Maven phase |
|---|---|---|---|
| Unit test | Validate isolated Java logic without Spring Boot startup, Docker, or external services. | JUnit, AssertJ, Mockito when needed | test |
| Integration test | Validate Spring wiring, HTTP controllers, persistence, Flyway, JPA, Config Client behavior, or Testcontainers-backed dependencies. | Spring Boot Test, MockMvc/RestTestClient, Testcontainers | integration-test and verify |
| Contract test | Validate API or event contracts between services. | OpenAPI, AsyncAPI, schema checks | future dedicated stage |
| SIT smoke test | Validate deployed services in Kubernetes through stable entry points. | kubectl, curl, Insomnia/manual checks |
deployment validation |
Node.js analogy:
- Unit test is like a Jest test for a pure function or service class.
- Integration test is like a Supertest/NestJS test that starts the app and uses a real PostgreSQL container.
- SIT smoke test is like calling deployed services through an API Gateway after containers are running.
Use names that tell Maven and humans what kind of test is being executed.
| Test kind | Class name pattern | Example |
|---|---|---|
| Unit test | *Test or *Tests |
CustomerServiceTest, AccountTest |
| Integration test | *IT or *IntegrationTest |
CustomerApiIT, AccountPersistenceIntegrationTest |
Recommended package placement:
src/test/java/com/digitalbank/<service>/
├── domain/
│ └── AccountTest.java
├── application/
│ └── AccountServiceTest.java
└── integration/
├── AccountApiIT.java
└── AccountPersistenceIT.java
The package structure is a readability convention. Maven decides what runs from the class name patterns configured in Surefire and Failsafe.
./mvnw testExpected behavior:
- Runs unit tests only.
- Does not start Testcontainers.
- Does not require Docker.
- Should be fast enough to run frequently while coding.
./mvnw verifyExpected behavior:
- Runs unit tests.
- Runs integration tests.
- May start Testcontainers.
- May start a Spring Boot application context.
- Is the default command before opening or updating a pull request.
Use Maven Surefire for unit tests and Maven Failsafe for integration tests.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<includes>
<include>**/*Test.java</include>
<include>**/*Tests.java</include>
</includes>
<excludes>
<exclude>**/*IT.java</exclude>
<exclude>**/*IntegrationTest.java</exclude>
<exclude>**/*IntegrationTests.java</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<includes>
<include>**/*IT.java</include>
<include>**/*IntegrationTest.java</include>
<include>**/*IntegrationTests.java</include>
</includes>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>The exact plugin versions should normally come from spring-boot-starter-parent unless a service has a specific reason to override them.
Use unit tests for:
- Domain rules.
- Application service orchestration that can use fake ports or mocks.
- Value object validation.
- Mapper behavior when the mapper does not require Spring.
- Error handling logic that does not need HTTP serialization.
Unit tests should not:
- Start the full Spring Boot application.
- Start PostgreSQL, Kafka, Redis, or other containers.
- Depend on Kubernetes, Config Server, or real network calls.
Use integration tests for:
- REST API behavior.
- Request validation and error response serialization.
- Spring dependency injection and configuration binding.
- Flyway migrations.
- JPA mappings and repository behavior.
- PostgreSQL persistence through Testcontainers.
- Config Server and API Gateway routing behavior.
Integration tests may use:
@SpringBootTest- Spring MVC/WebFlux test clients
- Testcontainers
- Real database migrations
- Application test profiles
Current Java service CI stage order:
-
Unit tests:
./mvnw test -
Integration tests and package verification without rerunning unit tests:
./mvnw verify -DskipUnitTests=true
-
Helm lint/template validation.
-
Container build and smoke test.
-
Quality gates, such as Spotless, Checkstyle, SpotBugs, and SonarQube, when added.
Why the integration stage uses -DskipUnitTests=true:
verifynormally includes thetestphase.- Running
verifydirectly aftertestwould execute the unit suite twice. - The explicit skip flag keeps the CI stages separate without losing the Failsafe-backed integration coverage.
This is the current production-style baseline for the Digital Bank Java platform.
For now, service repositories keep their own CI workflows instead of using a reusable workflow from .github.
Current decision:
- Keep per-service workflows first.
- Reuse the same command convention across services.
- Extract a reusable workflow later only after the service workflows stop diverging in meaningful ways.
Reasoning:
- The Maven test phases are now standardized.
- Container smoke tests still differ slightly by service because config payloads, ports, and dependency wiring are service-specific.
- Extracting too early would add indirection before the shape is stable.
jobs:
test:
steps:
- name: Run unit tests
run: ./mvnw --batch-mode --no-transfer-progress test
- name: Run integration tests
run: ./mvnw --batch-mode --no-transfer-progress verify -DskipUnitTests=trueThis is the preferred service-level pattern until a reusable workflow is introduced.
Apply the convention incrementally:
-
Rename existing Spring/Testcontainers tests to
*ITor*IntegrationTest. -
Keep pure domain/application tests as
*Testor*Tests. -
Add Surefire/Failsafe plugin configuration.
-
Run:
./mvnw test ./mvnw verify -
Update service README and CI workflow if command behavior changes.
Recommended CI test stages:
- name: Run unit tests run: ./mvnw --batch-mode --no-transfer-progress test - name: Run integration tests run: ./mvnw --batch-mode --no-transfer-progress verify -DskipUnitTests=true
Start with:
customer-serviceaccount-service
Then apply the same convention to future services as they gain domain logic and persistence.