Tests are part of the backend, not a bonus
On the SCM platform I did not stop at “the controller returns 200”. I built a QA chain: JUnit 5, Mockito, TestContainers, JaCoCo, then SonarQube in CI.
That chain is what lets JWT security and MVC layers change without fear. The security story is in the JWT article. The pipeline that consumes these tests is in GitHub Actions and Docker.
Layer the tests like you layer the code
Unit tests with JUnit 5 and Mockito
Services own procurement and delivery rules. Unit tests hit those services with mocked repositories. I assert:
- Invalid quantities never persist.
- A delivery cannot close twice.
- Security-related decisions in the service stay explicit.
Mockito is for collaborators, not for the class under test. If a test is 80% stubs, the design is probably wrong.
Integration tests with TestContainers
Controllers, security filters, and SQL need a real JVM HTTP stack and a real database. TestContainers boots that database in Docker. Flyway or Liquibase migrations run as they do in production.
Those tests are slower, so I keep them focused:
- Login then call a protected route.
- Create an order and read it back.
- Reject a request with an expired JWT.
JaCoCo and SonarQube
JaCoCo answers “did this line run?”. SonarQube answers “is this code a risk?”. I want both. Coverage on getters is vanity. Coverage on security config and domain services is the signal.
Sonar’s quality gate in GitHub Actions is a stop sign, not a dashboard decoration. If duplication or a blocker issue appears on a path that touches stock, the image does not publish.
A practical order of work
- Write the failing unit test for the rule.
- Implement the service.
- Add one integration test for the HTTP path.
- Check coverage on the files you actually changed.
- Let CI run Sonar.
That is slower than “commit and pray”. It is faster than debugging production inventory.
If you want this level of QA on a Java API, browse the work or send a message.
Frequently Asked Questions
When is Mockito enough?
When you are testing a service rule in isolation. Mock repositories and clocks. Do not mock the framework until the test is lying about production.
Why TestContainers instead of an H2 database?
H2 hides Postgres quirks. TestContainers runs the same engine your Docker Compose file uses, so schema and SQL stay honest.
Does JaCoCo replace code review?
No. Coverage tells you what never ran. Review still catches the wrong assertion on a green test.