diff --git a/docs/workshops/day_2_tdd.md b/docs/workshops/day_2_tdd.md index 91dd05b304eecbb868dc046163f187c6b709c798..561d0dcd366f488bf4dabe2a87294253b56b522d 100644 --- a/docs/workshops/day_2_tdd.md +++ b/docs/workshops/day_2_tdd.md @@ -369,12 +369,12 @@ Berikut adalah penjelasan terkait *test case* ini: ### Latihan Mandiri: Buat beberapa *negative case* - [ ] Buat *test case* `testPaymentCallbackWithSuccessfulStatusButCancelledDisbursement` pada *test suite* `CallbackServiceImplTest` untuk mengecek: - - [ ] Apakah fungsi `paymentCallback` memanggil **setidaknya satu kali** *helper function* `getPaymentLink` untuk akses API Flip? + - [ ] Apakah fungsi `paymentCallback` memanggil **setidaknya satu kali** *helper function* `disburseMoney` untuk akses API Flip? - [ ] Apakah fungsi `paymentCallback` memanggil **setidaknya satu kali** fungsi `save` pada `PaymentRepository` untuk menyimpan perubahan objek `Payment` ke dalam database? - [ ] Apakah fungsi `paymentCallback` mengembalikan objek `Payment` dengan `status` berupa `"DISBURSEMENT_FAILED"`? - **CATATAN**: `status` pada `disbursementResponse` harus diganti dengan `"CANCELLED"`. - [ ] Buat *test case* `testPaymentCallbackWithCancelledStatus` pada *test suite* `CallbackServiceImplTest` untuk mengecek: - - [ ] Apakah fungsi `paymentCallback` **TIDAK** memanggil *helper function* `getPaymentLink` untuk akses API Flip?<br /> + - [ ] Apakah fungsi `paymentCallback` **TIDAK** memanggil *helper function* `disburseMoney` untuk akses API Flip?<br /> **HINT**: gunakan ```java verify(service, atMost(0)).disburseMoney(any(DisbursementRequest.class)) @@ -460,7 +460,7 @@ Berikut adalah penjelasan mengenai *stubbing* pada *test case* ini: ### Tugas Anda - [ ] Buat *test case* `testPayToUserFailWhenSenderAndDestinationAreTheSame` sesuai dengan arahan yang sudah diberikan. - [ ] *Test case* diletakkan di dalam *test suite* `com.example.sibayar.service.payment.PaymentServiceImplTest`. - - [ ] Pastikan *test case* mengecek tiga hal yang disebutkan di arahan. + - [ ] Pastikan *test case* mengecek *exception* yang di-*throw* seperti yang disebutkan di arahan. - [ ] Buat *test case* `testPayToUserThrowsExceptionWhenAPIIsUnreachable` sesuai dengan arahan yang sudah diberikan. - [ ] *Test case* diletakkan di `com.example.sibayar.service.payment.PaymentServiceImplTest`. - [ ] Pastikan *test case* mengecek tiga hal yang disebutkan di arahan. @@ -574,6 +574,43 @@ Untuk bahan diskusi saat refleksi: Untuk hari ketiga, kita akan mendalami mengenai Functional Test dan Behaviour-Driven Development (BDD). +## Reflection Notes + +### Mengenai FIRST Principle + +1. **Fast** + - Proses *testing* harus dilakukan secara cepat, oleh karena itu *testing* `Service` dan komponen lain di Spring tidak menggunakan `MockMvc` layaknya di `Controller`. Hal ini karena di `Service`, kita cukup fokus dengan logic kita yang sudah terpisah dari dependensi *framework* Spring Boot. + - **Mengapa kita harus melakukan *mock* dan *stub* untuk akses *database*?**<br /> + Karena kita tidak ingin akses *database* memperlambat proses *testing* kita. Bahkan, kita sebisa mungkin menghindari alokasi *resource* tambahan untuk *database* terpisah hanya untuk *unit test*. +2. **Isolated** + - **Mengapa kita harus melakukan *mock* dan *stub* untuk akses *database*, *library*, atau API eksternal?**<br /> + Karena kita tidak ingin hasil dari proses eksekusi suatu *unit test* memengaruhi hasil *unit test* lain. + Dengan melakukan *mock* dan *stub* terhadap dependensi eksternal, kita tidak mengotori *data* pada dependensi eksternal tersebut dengan *dummy data* dari *unit test* kita. +3. **Repeatable** + - Aspek ini punya kaitan erat dengan aspek **Isolated**. Dengan *unit test* yang terisolasi, kita bisa mendapatkan hasil yang konsisten meskipun *testing* dilakukan berulang-ulang kali. +4. **Self-Validating** + - Aspek ini sudah otomatis ter-*cover* dengan penggunaan *testing library* JUnit, yang juga telah kita gunakan di tutorial. + - Pastikan saja setiap *unit test* memiliki 3A: + - **Arrange**: Persiapkan semua *data* dan argumen untuk *testing*. + - **Act**: Jalankan fungsi yang akan di-*test*. + - **Assert**: Lakukan pengecekan terhadap **hasil keluaran** dari fungsi yang di-*test*. Ini juga termasuk jika fungsi tersebut mengeluarkan *exception*. +5. **Thorough** + - Pastikan semua *happy path* dan *edge case* telah diuji. + - Lihat kembali *Acceptance Criteria* dari suatu *use case* untuk fungsi yang akan di-*test*. + +### Apakah Coverage 100% menjamin kode bersih dari bug? + +Tidak bisa menjamin. +Inilah pentingnya aspek **Thorough** pada FIRST Principle. + +Kalaupun aspek **Thorough** pada *unit test* sudah terpenuhi, kita juga masih tidak bisa menjamin program bebas bug ketika proses integrasi. +Oleh karena itu dibutuhkan *integration test* (yang akan dibahas lebih lanjut pada Day 3). + +Contoh sederhananya adalah pada test untuk `Controller` di SIBAYAR. +Ternyata walaupun Code Coverage dan Branch Coverage-nya sudah 100%, kita belum melakukan *test* untuk otorisasi (*endpoint* X hanya bisa diakses oleh *role* A). +Proses *test* untuk otorisasi di Spring Boot tidak bisa dilakukan dengan *unit test*, namun dengan *integration test*. +Dalam *integration test*, kita akan menjalankan aplikasinya secara keseluruhan, yang tentunya akan membutuhkan waktu eksekusi lebih lama dibandingkan *unit test*. + [1]: https://docs.google.com/presentation/d/1f1vpyYOu3GSyIeyqGLU-D6REBn0ACN81?rtpof=true&usp=drive_fs [2]: https://docs.flip.id/