Belajar Spring Boot - Testing & Quality Assurance
Episode 17 of 24

Belajar Spring Boot - Testing & Quality Assurance

Episode ini mengajarkan jaminan kualitas: unit testing dengan JUnit 5 dan Mockito, integration testing dengan @SpringBootTest dan @WebMvcTest, contract testing dengan Spring Cloud Contract, serta Testcontainers untuk database dan service dependencies.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Kode tanpa test adalah kode yang belum selesai. Episode 17 membahas testing dan quality assurance di Spring Boot — dari unit test yang cepat hingga integration test yang realistis dengan container sungguhan.

Kalian akan belajar menulis unit test dengan JUnit 5 dan Mockito, memakai slice test seperti @WebMvcTest, menguji interaksi antar service dengan Testcontainers, dan memahami contract testing untuk microservices.

Unit Testing dengan JUnit 5 dan Mockito

Struktur Test

Spring Boot menyediakan starter test yang membundel JUnit 5, Mockito, AssertJ, dan lain-lain:

Dependency starter test
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

Unit Test Service dengan Mock

Unit test fokus pada satu class; dependency diganti mock. Contoh menguji service yang bergantung pada repository:

Unit test dengan Mockito
@ExtendWith(MockitoExtension.class)
class ItemServiceTest {
 
    @Mock
    private ItemRepository repository;
 
    @InjectMocks
    private ItemService service;
 
    @Test
    void cariItemBerdasarkanId() {
        Item item = new Item(1L, "Laptop");
        when(repository.findById(1L)).thenReturn(Optional.of(item));
 
        Item hasil = service.findById(1L);
 
        assertThat(hasil.getName()).isEqualTo("Laptop");
        verify(repository).findById(1L);
    }
}

when(...).thenReturn(...) menyetel perilaku mock, dan verify(...) memastikan method benar-benar dipanggil. Unit test ini berjalan dalam milidetik tanpa database.

Integration Testing dengan @SpringBootTest

Memuat Seluruh Context

Untuk memastikan semua bean terpasang dengan benar, gunakan @SpringBootTest — test memuat seluruh application context:

Integration test dasar
@SpringBootTest
@AutoConfigureMockMvc
class ItemControllerTest {
 
    @Autowired
    private MockMvc mockMvc;
 
    @Test
    void listItemsMengembalikanStatusOk() throws Exception {
        mockMvc.perform(get("/api/items"))
                .andExpect(status().isOk());
    }
}

MockMvc mengirim request HTTP palsu tanpa memulai server sungguhan — cepat dan deterministik. Test ini memverifikasi bahwa controller, service, dan bean lain terhubung dengan benar.

Slice Test dengan @WebMvcTest

Untuk menguji controller secara terisolasi tanpa memuat seluruh context, gunakan @WebMvcTest. Hanya lapisan web yang dimuat, dependency lain di-mock:

Slice test WebMvc
@WebMvcTest(ItemController.class)
class ItemControllerSliceTest {
 
    @Autowired
    private MockMvc mockMvc;
 
    @MockBean
    private ItemService service;
 
    @Test
    void getItemMengembalikan404() throws Exception {
        when(service.findById(99L))
                .thenThrow(new ItemNotFoundException(99L));
 
        mockMvc.perform(get("/api/items/99"))
                .andExpect(status().isNotFound());
    }
}

@WebMvcTest jauh lebih cepat daripada @SpringBootTest karena hanya menyiapkan lapisan web. Test ini membuktikan bahwa perilaku HTTP — termasuk error handling dari episode 7 — bekerja dengan benar.

Testcontainers untuk Database dan Dependencies

Mengapa Test dengan Database Nyata

Database in-memory seperti H2 sering berbeda perilakunya dari PostgreSQL. Testcontainers menjalankan container Docker sungguhan selama test, sehingga test berjalan di environment yang sama dengan production:

Test dengan Testcontainers
@Testcontainers
@SpringBootTest
class ItemRepositoryTest {
 
    @Container
    static PostgreSQLContainer<?> postgres =
            new PostgreSQLContainer<>("postgres:16")
                    .withDatabaseName("belajar_test");
 
    @DynamicPropertySource
    static void setProperties(DynamicPropertyRegistry registry) {
        registry.add("spring.datasource.url", postgres::getJdbcUrl);
        registry.add("spring.datasource.username", postgres::getUsername);
        registry.add("spring.datasource.password", postgres::getPassword);
    }
 
    @Autowired
    private ItemRepository repository;
    // test query sungguhan di PostgreSQL
}

Container PostgreSQL dimulai sebelum test dan dihentikan setelahnya. Property datasource di-arahkan ke container lewat @DynamicPropertySource. Pastikan Docker berjalan di mesin development kalian.

Menguji Dependency Lain

Testcontainers juga menyediakan module untuk Redis, Kafka, Elasticsearch, dan lainnya. Pola yang sama — deklarasikan @Container, arahkan property, jalankan test — berlaku untuk semua service dependency.

Contract Testing dengan Spring Cloud Contract

Menjaga Kontrak Antar Service

Dalam microservices, perubahan tak terduga pada satu service bisa merusak service lain. Contract testing memastikan kedua sisi mematuhi kontrak yang disepakati. Dengan Spring Cloud Contract, kontrak ditulis di sisi producer dalam Groovy DSL — misalnya request GET /api/items/1 diharapkan membalas status 200 dengan body berisi id dan name.

Kontrak ini menghasilkan test di sisi producer dan stub di sisi consumer. Setiap perubahan kontrak akan langsung terdeteksi saat build — sebelum merusak integrasi di runtime.

Strategi Test yang Seimbang

Sebuah strategi yang baik menggabungkan semua level:

  • Unit test untuk logika bisnis — cepat, banyak, berjalan di CI.
  • Slice test untuk controller dan repository — medium, fokus per lapisan.
  • Integration test dengan Testcontainers untuk alur end-to-end yang kritis.
  • Contract test untuk batas antar service dalam microservices.
Jalankan seluruh test
./mvnw test

Perintah ./mvnw test menjalankan seluruh suite. Di CI/CD (episode 21), perintah ini menjadi gerbang sebelum aplikasi di-deploy.

Penutup

Episode 17 membekali kalian dengan jaminan kualitas: unit testing dengan JUnit 5 dan Mockito, integration testing dengan @SpringBootTest dan @WebMvcTest, contract testing dengan Spring Cloud Contract, serta Testcontainers untuk menguji database dan dependency sungguhan.

Inti yang harus dibawa pulang:

  • spring-boot-starter-test menyediakan JUnit 5, Mockito, dan AssertJ.
  • Unit test memakai mock dan berjalan dalam milidetik.
  • @SpringBootTest memuat seluruh context; @WebMvcTest hanya lapisan web.
  • Testcontainers menjalankan database nyata untuk integrasi yang realistis.
  • Contract testing menjaga batas antar service di microservices.
  • Kombinasikan unit, slice, integration, dan contract test secara seimbang.

Di episode 18 selanjutnya kita akan membahas modular architecture dan patterns — arsitektur clean, hexagonal, dan onion; struktur modul fitur dan package-by-feature; design patterns populer; serta event-driven architecture dengan Spring Events dan Kafka.

Belajar Spring Boot - Testing & Quality Assurance | Belajar Spring Boot