This episode covers testing in Java: unit testing with JUnit 5, mocking with Mockito and the test-driven development approach, integration testing, contract testing, and test containers, plus static analysis and linting tooling with SpotBugs, Checkstyle, and PMD.

Code without tests is code that is assumed broken. Episode 17 covers testing and quality assurance in Java — from unit testing with JUnit 5, mocking with Mockito, to integration testing, contract testing, and static analysis. You will build a safety net that makes refactoring safe.
Testing is not a formality; it is a culture. This episode introduces the tools and patterns that professional teams use to maintain code quality continuously.
JUnit 5 is the standard Java testing framework. Add the dependency:
mvn dependency:get -Dartifact=org.junit.jupiter:junit-jupiter:5.10.3The test structure: a class in src/test/java, methods with the @Test annotation and assertions:
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class KalkulatorTest {
@Test
void tambahMenghasilkanJumlah() {
Kalkulator kalkulator = new Kalkulator();
assertEquals(5, kalkulator.tambah(2, 3));
}
@Test
void bagiDenganNolMelemparException() {
Kalkulator kalkulator = new Kalkulator();
assertThrows(ArithmeticException.class,
() -> kalkulator.bagi(10, 0));
}
}assertEquals(5, kalkulator.tambah(2, 3)) verifies the expected result. Other assertions: assertTrue, assertNull, and assertThrows.
Run with Maven:
mvn testmvn test runs all tests in src/test/java and reports the results.
Mocking simulates external dependencies (databases, APIs) so unit tests focus on logic alone. Mockito is the most popular mocking library:
import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;
class LayananTest {
@Test
void ambilDataMemakaiRepository() {
Repositori repo = mock(Repositori.class);
when(repo.cari(1L)).thenReturn("Data");
Layanan layanan = new Layanan(repo);
assertEquals("Data", layanan.ambil(1L));
verify(repo).cari(1L);
}
}mock(Repositori.class) creates a mock object, when(...).thenReturn(...) defines its behavior, and verify ensures the method was called.
TDD works in short cycles: write a failing test, create the minimal implementation to make it pass, then refactor. This red-green-refactor cycle forces you to think about the specification before implementation.
An integration test verifies collaboration between components: the application with a database, message broker, or external service. These tests use real environments, not mocks.
Testcontainers runs real dependencies (databases, brokers) inside Docker while the test runs:
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.*;
@Testcontainers
class IntegrationTest {
@Container
static PostgreSQLContainer<?> postgres =
new PostgreSQLContainer<>("postgres:16");
@Test
void koneksiKeDatabaseNyata() {
String url = postgres.getJdbcUrl();
assertNotNull(url);
}
}new PostgreSQLContainer<>("postgres:16") starts a real PostgreSQL in Docker for realistic tests.
Contract testing verifies that two communicating services agree on the same API contract — preventing silent integration breakage. Popular tools: Spring Cloud Contract and Pact.
Static analysis inspects code without running it:
Add them as Maven plugins:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.4.0</version>
</plugin>
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<version>4.8.6</version>
</plugin>
</plugins>
</build>Run them during the build:
mvn verifymvn verify runs tests and static analysis together, making it an automatic quality gate.
Episode 17 covers testing and QA: unit testing with JUnit 5, mocking with Mockito and the TDD approach, integration testing, contract testing, and test containers, plus static analysis with SpotBugs, Checkstyle, and PMD.
Key takeaways:
@Test and assertions is the basis of unit testing.In the next episode, episode 18, we will discuss modular programming and project architecture — the modern Java Platform Module System, modularizing applications with module-info.java and dependency encapsulation, clean architecture, package-by-feature, and layered architecture, plus the important builder, factory, strategy, and observer design patterns. Time to design clean architecture!