Menjawab kebutuhan regression yang tahan flaky di Spring Boot

Tim yang mengelola aplikasi Spring Boot kehilangan kepercayaan pada regression suite ketika build sering merah bukan karena bug, tetapi akibat flaky test. Strategi yang berhasil memisahkan smoke dan regression suite, menjalankan regression dalam lingkungan yang konsisten via Testcontainers, dan mengukur flake rate akan langsung menjawab problem tersebut. Pendekatan ini memungkinkan tim mendeteksi regresi sebenarnya sekaligus mengidentifikasi dan memperbaiki test yang tidak stabil.

Artikel ini menunjukkan bagaimana merancang struktur suite, menyusun konfigurasi application-test.properties, menulis @SpringBootTest dengan data deterministik, serta menyusun pipeline CI/CD yang memverifikasi release tanpa mengorbankan kecepatan.

Membedakan smoke suite dan regression suite

Smoke suite adalah pengujian cepat yang memastikan komponen inti masih hidup selepas build. Regression suite mencakup skenario lebih luas. Untuk mendeteksi flaky test secara efektif, pisahkan keduanya dengan kriteria eksis:

  • Smoke: fokus pada endpoint utama dan kondisi layanan yang paling sering berubah; jalankan di pre-merge atau PR build.
  • Regression: mencakup alur bisnis lengkap dengan data kompleks, di-schedule secara nightly atau deployment candidate.

Regression suite berjalan lebih lama, sehingga harus dijalankan di environment yang sesuai agar tidak menghasilkan false positive. Prioritaskan test yang paling menerobos risiko produksi, dan gunakan tagging (@Tag("smoke"), @Tag("regression")) untuk seleksi suite di Gradle/Maven.

Menggunakan Testcontainers untuk menyamakan lingkungan pengetesan dengan produksi

Flaky test sering muncul karena perbedaan konfigurasi environment—database, broker, atau cache. Testcontainers menjalankan container Docker yang meniru dependency produksi dan bisa dikonfigurasi per suite.

Contoh application-test.properties minimal untuk memastikan Spring Boot mengarah ke kontainer Testcontainers:

spring.datasource.url=jdbc:tc:postgresql:14:///testdb?TC_INITSCRIPT=classpath:init.sql
spring.datasource.username=test
spring.datasource.password=test
spring.jpa.hibernate.ddl-auto=validate
logging.level.org.springframework.test.context=DEBUG

Gunakan jdbc:tc: untuk menghidupkan PostgreSQL saat test dijalankan, lalu biarkan Testcontainers mengelola lifecycle-nya. Pastikan konfigurasi ini juga digunakan pada regression suite agar hasilnya konsisten dengan produksi.

Praktik tambahan

  • Shared container: Bila layanan Anda terhubung ke Redis, Kafka, atau Elasticsearch, buat container di @Testcontainers pada kelas dasar dan gunakan kembali di semua test.
  • Cek readiness: Jangan anggap aplikasi sudah siap hanya karena kontainer hidup—tambahkan eksplisit health check atau tunda interaksi hingga container siap.

Membangun @SpringBootTest dengan data deterministik

Untuk memastikan regression suite tidak menghasilkan hasil acak, gunakan data deterministik yang sama di setiap run.

@SpringBootTest
@Testcontainers
@ActiveProfiles("test")
class OrderServiceRegressionTest {
    @Container
    static PostgreSQLContainer postgres = new PostgreSQLContainer<>("postgres:14");

    @DynamicPropertySource
    static void overrideProperties(DynamicPropertyRegistry registry) {
        registry.add("spring.datasource.url", postgres::getJdbcUrl);
        registry.add("spring.datasource.username", postgres::getUsername);
        registry.add("spring.datasource.password", postgres::getPassword);
    }

    @Autowired
    OrderService orderService;

    @Test
    void prosesPesananDeterministik() {
        // Pastikan data awal selalu sama
        orderService.resetForRegressionTest();
        var result = orderService.processOrder("SKU-123", 2);
        assertThat(result.getStatus()).isEqualTo(OrderStatus.CONFIRMED);
    }
}

Metode resetForRegressionTest() harus menyiapkan data awal yang konsisten—misalnya, membersihkan tabel dan memasukkan catalog statis. Hindari seed data yang diambil dari waktu nyata atau API eksternal agar tidak memperkenalkan nondeterminisme.

Mendeteksi dan memonitor flake rate

Flake rate adalah persentase test yang gagal secara sporadis. Tanpa monitoring, flaky test bisa tercecer dalam regression suite dan kembali menyebabkan ketidakpercayaan.

  • Gunakan tool CI yang bisa menyimpan sejarah hasil test dan mengelompokkan berdasarkan nama test atau tag.
  • Hitung flake rate dengan pola: (gagal sebelumnya lalu sukses di run berikutnya). Perluasan berupa pelaporan test yang gagal dua kali berturut-turut tanpa perubahan kode.
  • Laporkan secara reguler: output grafis atau notifikasi ke tim devops bila flake rate suatu test melebihi ambang (misal 5%).

Debugging flaky test juga penting—ambil logs dan stack trace dari run yang gagal. Jangan abaikan peringatan timing atau race condition; biasanya menunjukkan bahwa test tidak menunggu readiness dependency.

Integrasi regression suite ke pipeline CI/CD

Langkah-langkah berikut membantu memastikan regression suite dan monitoring flake rate dijalankan sebelum release:

  1. Stage smoke: jalankan di PR build dengan tagging smoke untuk hasil cepat.
  2. Stage regression: jalankan nightly atau di branch release candidate. Gunakan runner khusus dengan resource lebih besar agar Testcontainers tidak terkendala.
  3. Collect artifacts: simpan logs, test report, dan grafik flake rate setiap run regression;
  4. Threshold gating: Hentikan deployment bila flake rate di atas ambang atau ada test yang gagal lebih dari sekali tanpa perubahan kode.
  5. Promosi release: Setelah regression suite bersih, update artefak build (misal versi Docker image) lalu lanjutkan ke environment staging/production.

Integration example (CI):

stages:
  - smoke
  - regression
  - deploy

smoke_tests:
  script: ./gradlew test --tests *Smoke*
  tags:
    - docker

regression_tests:
  script: ./gradlew test --tests *Regression* --info
  when: manual
  allow_failure: false
  artifacts:
    paths:
      - build/test-results

analyze_flakes:
  script: python scripts/flake_monitor.py build/test-results
  dependencies:
    - regression_tests

Script flake_monitor.py bisa membaca report XML untuk menghitung flake rate dan mengirim notifikasi bila ada tes yang bergagal-sukses bolak-balik.

Penutup

Strategi regression testing di Spring Boot harus mempertimbangkan pemisahan suite, determinisme data, lingkungan yang mirip produksi dengan Testcontainers, dan monitoring flaky test. Integrasi ke pipeline CI/CD memastikan build release tidak lolos dengan regression issue. Dengan pendekatan ini, tim dapat mendeteksi regresi substansial tanpa mengorbankan kecepatan delivery.