Topik ini membahas penulisan pengujian otomatis dengan modul inti Test::More. Pembahasan mencakup struktur berkas pengujian, plan berupa jumlah pengujian yang dijanjikan, fungsi perbandingan seperti ok dan is, format keluaran TAP yang dicetaknya, cara membaca hasil pengujian yang gagal, serta pelaksanaannya dengan perintah prove. Setelah topik ini diikuti, perilaku sebuah subrutin dapat dikunci oleh pengujian yang berjalan ulang kapan pun diperlukan.
Struktur berkas pengujian#
Berkas pengujian Perl lazim diberi ekstensi .t dan memuat modul Test::More pada baris awalnya. Angka pada use Test::More tests => 7 adalah plan, yaitu janji jumlah pengujian yang akan dijalankan. Berkat plan itu, program pengujian dapat menandai kelalaian bila pengujian berhenti sebelum jumlahnya tercapai. Subrutin yang diuji didefinisikan di dalam berkas yang sama agar pengujian tetap mandiri.
#!/usr/bin/perl
use strict;
use warnings;
use Test::More tests => 7;
# subrutin yang diuji: konversi suhu Celsius ke Fahrenheit
sub konversi_c_ke_f {
my ($celsius) = @_;
return $celsius * 9 / 5 + 32;
}
# ok menguji satu pernyataan bernilai benar atau salah
ok(defined &konversi_c_ke_f, 'subrutin konversi_c_ke_f tersedia');
# is membandingkan dua nilai dengan eq
is(konversi_c_ke_f(0), 32, 'titik beku air bernilai 32 F');
is(konversi_c_ke_f(100), 212, 'titik didih air bernilai 212 F');
# isnt memastikan dua nilai tidak sama
isnt(konversi_c_ke_f(37), 100, 'suhu tubuh tidak bernilai 100 F');
# like menguji kecocokan dengan pola regex
like(konversi_c_ke_f(25), qr/^\d+$/, 'hasil 25 C berupa bilangan bulat');
# cmp_ok membandingkan dengan operator apa pun
cmp_ok(konversi_c_ke_f(40), '>', konversi_c_ke_f(20), '40 C lebih tinggi daripada 20 C');
# is_deeply membandingkan dua struktur data
my @titik = (konversi_c_ke_f(0), konversi_c_ke_f(100));
is_deeply(\@titik, [ 32, 212 ], 'dua titik acuan sesuai');1..7
ok 1 - subrutin konversi_c_ke_f tersedia
ok 2 - titik beku air bernilai 32 F
ok 3 - titik didih air bernilai 212 F
ok 4 - suhu tubuh tidak bernilai 100 F
ok 5 - hasil 25 C berupa bilangan bulat
ok 6 - 40 C lebih tinggi daripada 20 C
ok 7 - dua titik acuan sesuaiSetiap pemanggilan fungsi pengujian menghasilkan satu baris keluaran, dan seluruhnya lulus karena nilai yang dibandingkan sesuai harapan. Argumen terakhir setiap fungsi adalah deskripsi pengujian yang teksnya bebas, tetapi sebaiknya menyatakan perilaku yang diharapkan. Deskripsi yang baik membuat daftar keluaran dapat dibaca tanpa membuka kembali kodenya.
Ekstensi .t bukan keharusan bagi perl, melainkan konvensi yang digunakan prove dan peralatan pembangunan untuk mengenali berkas pengujian. Pada proyek yang lebih besar, berkas tersebut lazim dikumpulkan dalam direktori bernama t di samping kode sumbernya. Fungsi pengujian seperti ok dan is diekspor oleh Test::More pada saat use, sehingga keduanya dipanggil langsung tanpa awalan nama paket. Subrutin yang diuji pada contoh ini didefinisikan di dalam berkas yang sama agar berkasnya mandiri, sedangkan pada proyek nyata subrutin tersebut pindah ke modul yang dimuat melalui pernyataan use lib.
Fungsi perbandingan Test::More#
Test::More menyediakan satu keluarga fungsi dengan tugas yang terbagi rapi. Pemilihan fungsinya menentukan ketajaman diagnostik ketika pengujian gagal, karena tiap fungsi melaporkan kegagalannya dengan cara berbeda.
| Fungsi | Tugas |
|---|---|
ok | Menguji satu pernyataan yang bernilai benar atau salah |
is dan isnt | Membandingkan dua nilai string dengan eq dan ne |
like | Menguji kecocokan nilai terhadap pola regex |
cmp_ok | Membandingkan dua nilai dengan operator apa pun, termasuk operator angka |
is_deeply | Membandingkan dua struktur data secara menyeluruh |
Fungsi is menjadi pilihan utama untuk nilai yang diketahui persis, karena kegagalannya dilengkapi nilai yang didapat dan nilai yang diharapkan. Fungsi isnt membalik arah pengujian yang sama. Fungsi cmp_ok digunakan ketika perbandingannya melibatkan angka, misalnya lebih besar atau lebih kecil, karena is membandingkan string dan menganggap dua tulisan berbeda sebagai dua nilai berbeda. Fungsi is_deeply menelusuri struktur referensi dan membandingkan isinya butir demi butir, sehingga array hasil konversi dapat diuji terhadap array harapan dalam satu pemanggilan.
Fungsi is memperlakukan nilai tak tentu sebagai kasus khusus, sehingga variabel yang belum terisi dapat dibandingkan dengan undef secara andal. Pada like, argumen kedua ditulis dengan qr//, dan pola yang sama dapat digunakan ulang di beberapa pemanggilan. Fungsi is_deeply melaporkan perbedaan pertama yang ditemukannya, sehingga struktur bersarang yang gagal dapat dilacak sampai ke butirnya.
Format keluaran TAP#
Keluaran pada bagian sebelumnya mengikuti format TAP (Test Anything Protocol), yaitu format teks polos yang dibaca oleh program pemeriksa pengujian. Baris pertamanya adalah plan berisi jumlah pengujian yang dijanjikan, yaitu 1..7. Setiap pengujian menghasilkan satu baris yang dimulai dengan ok atau not ok, diikuti nomor urut dan deskripsinya. Baris yang dimulai dengan tanda pagar adalah komentar untuk manusia dan diabaikan oleh pembaca TAP. Kesederhanaan format inilah yang membuat hasil pengujian dapat dikumpulkan oleh Test::Harness tanpa perlu memahami kode Perl yang menghasilkannya.
Plan dapat muncul di awal maupun di akhir aliran, dan keduanya diterima pembaca TAP. Setelah deskripsi, baris pengujian boleh membawa arahan berupa # TODO atau # SKIP. Baris dengan arahan # TODO tetap terhitung meskipun hasilnya gagal, sedangkan baris dengan arahan # SKIP dilewati. Keduanya menyertakan alasan tertulis di belakang tanda pagar, sehingga laporan tetap menjelaskan mengapa satu pengujian tidak dinilai.
Pesan tambahan yang dicetak oleh fungsi diag tampil sebagai baris komentar diawali tanda pagar, sehingga tidak mengganggu pembacaan hasil. Aliran TAP dapat pula diakhiri baris Bail out! apabila error yang terjadi membuat pengujian berikutnya tidak bermakna. Format ini tidak terbatas pada Perl, karena isinya teks polos yang dapat dibaca program pemeriksa dari bahasa lain.
Membaca hasil pengujian yang gagal#
Pengujian yang gagal justru memperlihatkan kekuatan format TAP. Berkas berikut sengaja memuat satu pengujian yang keliru agar diagnosanya dapat diamati, dan pelaksanaannya ditunjukkan melalui blok bash karena diagnosanya menyebut nama berkasnya.
# tidak-dijalankan: diagnosanya memuat nama skrip, peragaannya ada pada blok bash di bawah
use strict;
use warnings;
use Test::More tests => 2;
# pengujian yang sengaja dibuat gagal untuk melihat diagnosanya
is(2 + 2, 5, 'penjumlahan dasar');
ok(1, 'pengujian kedua lulus');# menjalankan berkas pengujian yang gagal dari direktori berkasnya
perl pengujian-gagal.t 2>&11..2
not ok 1 - penjumlahan dasar
# Failed test 'penjumlahan dasar'
# at pengujian-gagal.t line 8.
# got: '4'
# expected: '5'
ok 2 - pengujian kedua lulus
# Looks like you failed 1 test of 2.Baris not ok menandai pengujian pertama yang gagal, kemudian diikuti komentar diagnostik dari fungsi is, yaitu nilai yang didapat (got) dan nilai yang diharapkan (expected). Diagnostik sedetail ini hanya muncul karena yang digunakan adalah is, bukan ok yang hanya melaporkan benar atau salah. Baris terakhir merangkum jumlah kegagalan, dan program berakhir dengan status keluar bukan nol, yaitu 1 pada eksekusi di atas. Status bukan nol itulah yang dibaca oleh alat pelaksana pengujian untuk menandai kegagalan.
Seluruh baris diagnostik pada keluaran tersebut diawali tanda pagar, sehingga pembaca TAP tidak menafsirkannya sebagai baris hasil. Baris not ok tetap menjadi satu-satunya penanda kegagalan bagi program pemeriksa, sedangkan baris komentarnya ditujukan bagi manusia yang membaca keluarannya. Apabila terdapat beberapa kegagalan dalam satu berkas, baris not ok muncul untuk masing-masing, sedangkan baris ringkasan di akhir melaporkan jumlahnya. Pada pelaksanaan melalui prove, detail semacam ini baru tampil apabila opsi -v digunakan.
done_testing sebagai alternatif plan#
Plan dapat dinyatakan di akhir alih-alih di awal. Fungsi done_testing dijalankan setelah seluruh pemanggilan pengujian, dan jumlah pengujian yang terhitung menjadi plan penggantinya. Bentuk ini cocok ketika jumlah pengujian tidak mudah dihitung lebih dahulu, misalnya karena bergantung pada data. Perhatikan bahwa plan pada keluarannya tercetak setelah baris pengujian, karena baris itu baru terbentuk pada akhirnya.
Tanpa plan di awal, pengujian yang berhenti mendadak tidak meninggalkan plan sama sekali, dan pembaca TAP melaporkan alirannya sebagai keluaran tanpa plan. Kondisi tersebut tetap tercatat sebagai kegagalan, sehingga pengaman janji jumlah pengujian tidak hilang sepenuhnya. Fungsi done_testing juga menerima angka opsional untuk menegaskan jumlah yang diharapkan, dan ketidakcocokannya dilaporkan sebagai error. Bentuk tanpa argumen lebih umum karena Test::More menghitung jumlah pengujian yang telah berjalan sendiri.
# done_testing menutup pengujian tanpa plan di awal
perl -e 'use Test::More; ok(2 > 1, "dua lebih besar dari satu"); done_testing()'ok 1 - dua lebih besar dari satu
1..1Menjalankan pengujian dengan prove#
Perintah prove melaksanakan berkas pengujian dan merangkum hasilnya dalam satu baris laporan berisi jumlah lulus dan gagal beserta waktu eksekusinya. Karena laporan itu memuat pengukuran waktu yang berubah pada setiap eksekusi, perintah berikut tidak disertai keluaran dan cukup dijalankan sendiri pada terminal.
Perintah prove dapat menerima beberapa berkas sekaligus dan mengeksekusinya berurutan sebelum merangkum semuanya dalam laporan akhir. Opsi -r menelusuri direktori secara berulang, sehingga seluruh berkas .t di dalamnya dijalankan tanpa disebut satu per satu. Opsi -l menambahkan direktori lib proyek ke @INC, sehingga modul yang diuji dapat dimuat tanpa pengaturan tambahan. Perintah ini berakhir dengan status keluar bukan nol apabila ada pengujian yang gagal, sehingga dapat dirangkai dalam skrip pembangunan.
# tidak-dijalankan
# menjalankan satu berkas pengujian dengan ringkasan singkat
prove pengujian.t
# menampilkan TAP lengkap dengan opsi -v
prove -v pengujian.tprove menjalankan berkas yang disebutkan dan mencetak ringkasannya tanpa menampilkan setiap baris TAP, sedangkan opsi -v menampilkan TAP lengkap sebagaimana keluaran pada bagian sebelumnya. Opsi -v digunakan ketika sebuah pengujian gagal dan diagnosanya perlu dibaca langsung.
Pola pelaksanaan yang sama digunakan pada proyek akhir di modul Pengerjaan Proyek, yaitu berkas pengujian diletakkan di samping kode proyek dan dijalankan melalui prove.
Kesalahan umum#
- Jumlah pemanggilan fungsi pengujian tidak cocok dengan plan yang dijanjikan, misalnya
tests => 7tetapi hanya terdapat enam pemanggilan, sehingga laporan berakhir gagal meskipun seluruh pengujian lulus. Perbaikannya adalah menyamakan angka plan dengan jumlah pengujian atau beralih kedone_testing. - Pernyataan perbandingan dimasukkan ke
ok, misalnyaok($hasil == 32), sehingga kegagalannya tidak menyertakan nilai yang didapat dan nilai yang diharapkan. Perbaikannya adalah menggunakanisataucmp_okagar diagnostiknya lengkap. - Deskripsi pengujian dibiarkan kosong sehingga baris TAP hanya berisi
ok 3tanpa keterangan, dan kegagalan menjadi sulit dicari. Perbaikannya adalah menuliskan deskripsi singkat yang menyatakan perilaku yang diharapkan.
Ringkasan#
- Berkas pengujian memuat Test::More beserta plan berupa
tests => Natau penutupdone_testing, dan lazim disimpan dengan ekstensi.t. - Fungsi
ok,is,isnt,like,cmp_ok, danis_deeplymembagi tugas perbandingan, dan pilihannya menentukan detail diagnostik saat gagal. - Keluaran pengujian mengikuti format TAP berupa plan serta baris
okataunot okyang dapat dibaca Test::Harness. - Perintah prove melaksanakan berkas pengujian dan merangkum hasilnya, dengan opsi
-vuntuk menampilkan TAP lengkap.
Referensi#
- Test::More — dokumentasi resmi Perl
— Rujukan fungsi
ok,is,isnt,like,cmp_ok,is_deeply, serta plan dandone_testing. - Test::Harness — dokumentasi resmi Perl — Menjelaskan pembacaan format TAP dan pelaksanaan pengujian yang menjadi dasar perintah prove.