Membuat Unit Test Yang Melibatkan Waktu
Pada suatu hari, saya ingin membuat unit test untuk menguji kode program yang menggunakan setInterval()
. Bagaimana caranya memastikan bahwa kode program sudah benar melakukan sebuah operasi secara berulang kali, tanpa harus menunggu? Contoh lain yang berkaitan dengan waktu adalah menguji kode program yang akan mengirim notifikasi kegagalan bila tidak ada respon yang diterima selama 30 menit. Bagaimana cara memastikan bahwa kode program tersebut telah benar tanpa harus menunggu 30 menit?
Sebagai contoh, kode program yang diuji adalah:
Kode program di atas akan mengirim pesan ke PubSub selama 10 kali setiap menit sejak waktu yang ditetapkan oleh variabel dari
. Bagaimana caranya supaya saya bisa memastikan kode program di atas berjalan dengan benar? Eksekusi manual dengan menunggu hingga 10 menit untuk melihat apakah terdapat output setiap menit akan sangat membosankan. Memanggil langsung dari unit test tanpa melakukan mocking untuk timers sama saja akan menunggu 10 menit. Salah satu solusi untuk memanipulasi waktu (seperti mempercepat tick), bila menggunakan Sinon untuk pengujian, adalah dengan menggunakan fasilitas yang ada di https://sinonjs.org/releases/latest/fake-timers/.
Sebagai langkah pertama, saya akan menguji skenario dimana dari
tidak boleh di masa lalu sebelum waktu dimana mulai()
dipanggil. Bila dari
di masa lalu, pemanggilan mulai()
harus men-throw Error
. Pada latihan ini, saya menggunakan Mocha sebagai testing framework dan API assert bawaan Node.js untuk assertion (sebagai alternatif, terdapat juga library populer seperti should.js, expect.js, chai, dan sebagainya). Ini contoh unit test yang saya buat:
Pada skenario di atas, saya menggunakan useFakeTimers
supaya setiap kali terdapat kode program yang mencari waktu saat ini
seperti new Date()
dan moment()
akan mengembalikan waktu yang dirujuk oleh variabel sekarang
. Karena dari
berisi
waktu lebih awal satu jam dari sekarang
, maka proses.mulai(dari)
harus melempar kesalahan Error
. Bila tidak, maka
ada yang salah dengan kode program saya.
Berikutnya, saya akan memastikan bahwa terdapat jeda dimana operasi pengiriman pesan hanya akan dimulai setelah mencapai waktu
yang ditentukan oleh variabel dari
. Selain itu, agar lebih singkat, saya juga memastikan bahwa pesan ke PubSub akan dikirim
sebanyak 10 kali selama 10 menit. Hasil akhir dari unit test saya terlihat seperti berikut ini:
Pada unit test di atas, saya menggunakan clock.tick()
untuk memajukan waktu secara synchronous. Pada awalnya adalah jam 03:00:00
.
Setelah clock.tick('00:30:00')
, jam akan berubah menjadi 03:30:00
. Dengan demikian, saya bisa memajukan waktu secara cepat
tanpa harus menunggu sama sekali. Dengan membuat stub untuk method publish()
di Topic
, saya bisa menggunakan sinon.assert.callCount()
untuk
memastikan stub tersebut dipanggil 10 kali.
Sebagai contoh, saya tidak bisa melakukan pemanggilan aktual ke server PubSub di unit test di atas. Agar lebih mudah mereplikasikannya, saya akan
merujuk pada contoh kode program tanpa useFakeTimers()
yang lolos pengujian tanpa masalah:
Akan tetapi, begitu saya menambahkan useFakeTimers()
seperti berikut ini:
Skenario di atas akan berakhir dengan kegagalan. Setelah clock.tick()
, pengiriman pesan ke PubSub tidak kunjung selesai juga
sehingga saya tidak bisa menganggap bahwa seluruh timers sudah menjadi synchronous (seperti di awal artikel ini). Terlihat bahwa
dengan melakukan stubbing API yang berkaitan dengan waktu, library PubSub menjadi tidak berkerja sebagaimana seharusnya. Tentu saja
tidak akan masalah bisa library tersebut ikut di-stub juga.