Ruthless Testing 5

Posted on December 1st, 2006 | by Endy Muhardin |

Setelah beberapa seri artikel Ruthless Testing, ternyata lebih banyak yang skeptis daripada yang antusias. Respon yang paling banyak ditemukan adalah:

> Wah, ini konsep yang sangat menarik. Tentunya akan sangat baik jika diterapkan. Sayang sekali, di tempat saya tidak bisa, karena … [berbagai alasan dan kesulitan] …

Hmm … saya mengerti perasaan Anda. Been there, done that. Saya pernah jadi programmer, dan juga pernah jadi project manager. Saya mengerti beberapa keberatan dan kesulitan implementasinya.

Daripada berkeluh kesah tiada guna, mari kita lihat satu persatu masalahnya.

Programmer : Bikin unit test? Nambah kerjaan aja. Lagian test code kan gak dideliver ke client

Jawaban saya:
Unit test itu adalah investasi Anda. Bayangkan beberapa bulan/tahun yang akan datang, client datang ke kita, meminta perbaikan untuk error dalam aplikasi. Padahal kita sedang sibuk mengerjakan proyek lain yang sama sekali berbeda. Hampir seluruh kode sudah kita lupakan. Bahkan untuk method sederhana seperti ini

calc.divide(x, y);

kita sudah lupa bagaimana behaviournya kalau menghadapi pembagian dengan nol, bilangan negatif, atau bilangan tidak bulat. Dan seperti biasa, kita tidak membuat komentar Javadoc.

*Unit test to the rescue*. Tinggal buka unit test untuk kode di atas, dan kita akan melihat bagaimana kode tersebut menghadapi bilangan negatif, nol, dan kasus-kasus aneh lainnya.

Next ..

Programmer : Aplikasi saya mengakses jaringan/database/email. Sulit dites

Jawaban saya:
Itu namanya integration testing, bukan unit testing. Walaupun demikian, tetap bisa dites secara otomatis. Tapi butuh sedikit investasi tambahan.

Misalnya, kita punya method seperti ini:

public void process(Order order) {
// coba lihat customernya, periksa saldonya
Customer c = order.getCustomer();
if(c.getBalance() < 0) {
// handle error
}

// saldo ok, simpan order ke database
String sql = "INSERT INTO tbl_order VALUES (?, ?, ?)";

// kirim email konfirmasi
String dest = c.getEmail();
// kode send email tidak ditunjukkan
}

Seperti kita lihat, ada beberapa integration point di sini, yaitu akses database dan koneksi ke mail server.

Untuk mengotomasi pengetesan method ini, kita gunakan teknik yang sudah teruji dari 400 tahun lalu: *divide et impera*. Yang tidak tidur di kelas waktu pelajaran Sejarah pasti tau teknik ini.
Sekarang teknik ini sudah diadaptasi ke dunia programming dengan istilah Refactoring. Silahkan google keyword tersebut untuk lebih jelasnya.

Pada contoh kita di atas, kita me-refactor kode akses database dan koneksi mail server ke class yang berbeda. Kita pisahkan kode tersebut ke class tersendiri. Berikut adalah interfacenya:

public interface OrderDao {
public void save(Order o);
}

dan

public interface MailSender {
public void send(String from, String to, String message);
}

Implementasinya disisakan buat latihan di rumah.

Sehingga method kita menjadi seperti ini:

public void process(Order order) {
// coba lihat customernya, periksa saldonya
Customer c = order.getCustomer();
if(c.getBalance() < 0) {
// handle error
}

orderDao.save(order);

mailSender.send(adminEmail, c.getEmail(), "Order sudah dikirim");
}

Dengan adanya kedua class tambahan ini, kita bisa menggunakan [Mock Object](http://www.easymock.org/ "Salah satu implementasi mock object") untuk memalsukan object orderDao dan mailSender. Kita bisa buat kedua object ini selalu sukses, atau selalu gagal, tergantung skenario yang mau dites.

OrderDao sendiri bisa dites dengan menggunakan [teknik pengetesan database](http://endy.artivisi.com/blog/java/ruthless-testing-4/ "Database Testing"). MailSender dapat ditest dengan menggunakan [Dumbster](http://quintanasoft.com/dumbster/ "Mail Server Palsu"), mail server palsu.

Kasus seperti ini biasanya terjadi karena kodenya sudah terlanjur campur aduk. Apabila unit test diterapkan dari awal project, programmer terkondisi untuk membuat kode yang mudah dites, sehingga effort untuk refactor tidak terlalu besar.

Tujuan utama kita adalah semua tes bisa dijalankan otomatis, independen (tes satu tidak mempengaruhi tes lain) dan *repeatable*(bisa diulang-ulang dengan hasil yang konsisten).
Tidak harus menggunakan JUnit. Bisa pakai tools buatan sendiri.

Keberatan berikutnya datang dari project manager.

Project Manager : Berarti saya harus alokasikan waktu tambahan untuk membuat unit test, wah bisa-bisa saya dimarahi client/bos.

Jawaban saya:
Bos… programmer Anda *pasti* membuat kode test, walaupun tidak otomatis. Ini sudah naluri dasar manusia.

Berikut contohnya:

public void process(Order order) {
// coba lihat customernya, periksa saldonya

// saldo ok, simpan order ke database
String sql = “INSERT INTO tbl_order VALUES (?, ?, ?)”;

// coba periksa … nanti kita hapus lagi
String coba = “SELECT * FROM tbl_order WHERE .. “;

// kirim email konfirmasi
String dest = c.getEmail();
// kode send email tidak ditunjukkan
}

Jadi, daripada dia pasang kode test di kode program, dan nantinya dihapus lagi, kan sayang. Lebih baik suruh saja untuk bikin unit test betulan.
Keuntungan berikutnya, dengan banyaknya unit test, kesalahan coding akan lebih cepat ditemukan, sehingga pada tahap testing oleh client, lebih sedikit bug yang ditemukan.
Dengan demikian, alokasi waktu untuk rework akan lebih sedikit.

Project Manager : Kalau terlalu banyak unit test, nanti aplikasinya menjadi rumit.

Jawaban saya:
Justru sebaliknya. Aplikasi yang banyak unit testnya akan menjadi lebih modular dan tidak terlalu kusut struktur internalnya. Dengan demikian, kode program menjadi lebih mudah dipelihara dan dikembangkan.

Terakhir, ada beberapa tips dari saya agar penerapan unit testing dapat berjalan dengan optimal:

* siapkan infrastruktur sebelum mulai coding
* sering-sering refactor agar kode mudah dites
* gunakan coverage testing sebagai pelengkap, agar kekurangan unit test cepat terdeteksi
* terapkan daily build otomatis yang menjalankan semua tes

Demikian, semoga bermanfaat

  1. 8 Responses to “Ruthless Testing 5”

  2. By Andry on Dec 11, 2006 | Reply

    Kan tidak semuanya harus ditest? Untuk presentation layer misalnya. Bisa saja cuma pake simulasi kan? Seperti pake watir/watij itu.

    Untuk unit testing, masalah yang saya hadapi cenderung kultural. Di organisasi besar, pilihan metodologinya birokratis alias waterfall. Di kultur “big requirement/design up front”, tidak ada alokasi waktu untuk unit testing. Test, ya dianggap jadi satu dengan development.

    Itu yang saya alami sekarang. Bukan karena semua pihak skeptis terhadap keajaiban junit/nunit, tapi karena kultur yang kaku itu.

  3. By Nanda Firdausi on Dec 13, 2006 | Reply

    to Andry:

    Justru karena development bersatu dengan test maka unit test adalah jawaban terbaik. Bahkan sekalipun ada waktu khusus untuk test, maka itu harusnya adalah integration test dan bukan lagi unit test.

  4. By Endy Muhardin on Dec 14, 2006 | Reply

    Kan tidak semuanya harus ditest?
    Untuk presentation layer misalnya.
    Bisa saja cuma pake simulasi kan?
    Seperti pake watir/watij itu.

    Ya tidak semua harus ditest. Saya sendiri biasanya cuma pakai JUnit untuk method kalkulasi bisnis dan akses database.
    Untuk presentation layer, lebih efektif pakai functional testing seperti Watir atau Selenium.

    Setuju dengan Nanda. Waktu test sebaiknya digunakan untuk integration, performance, stress, dan functional testing.

  5. By Syafrudin on Dec 19, 2006 | Reply

    Bagi yang berkecimpung di dunia “Safety-Critical Software” segi keselamatan, mutu, dan pengujian P/L sangat diperhatikan, bahkan untuk segi kesalamatan ada kriteria SIL (Safety Integrity Level) 1 sampai 4, hanya P/L dengan SIL 4 yang bisa digunakan misalnya untuk avionik pesawat terbang.

    Karena sudah biasa dengan kebanyakan masyarakat pengembangan P/L di Indonesia “skeptis” terhadap segi keselamatan, mutu, dan pengujian P/L, saya justru gembira sekali kalau ketemu orang yang memperhatikan aspek - aspek tersebut.

  6. By joshua on May 31, 2007 | Reply

    Unit testing itu ide yang bagus untuk diterapkan di project. Tapi dengan syarat setiap layer itu harus bisa di decouple. Nah selama ini saya belum pernah dapat project seperti itu. Sekarang aja untuk data access layer-nya terikat kuat dengan si Datasource dari Appserver-nya. Belum lagi layer EJB-nya. Untuk data Belum lagi layer Struts-nya. Belum lagi semua library untuk runtime appserver. Aaah. Yah memang bisa pake mock object untuk data access dan struts siy. And I will invest some time for this, walaupun gak semudah framework lain yang bisa di decouple per potong buat testing. Karena capek banget nge-test di screen dan harus deploy ke appserver dulu.

  7. By MIchsan on Jun 5, 2007 | Reply

    Keren banget. Saya salut sama orang yang sangat menghargai pemeliharaan kode. Terutama dengan testing ini. Memang stress kalo testing di akhir. Ada perasaan was was. Kent Beck (Orang XP terkenal, penemu JUnit) memahami masalah stress yang bisa menimpa programmer ini. Rasa tidak percaya diri untuk melanjutkan atau memperbesar kode apalagi memodifikasi kode. Saya jadi ingin bekerja di lingkungan orang2 Agile terutama XP.

    Saya pernah sih pake XP untuk menentukan behaviour suatu class aja. Padahal XP itu digunakan sangat menyeluruh termasuk memanage proyek agar tidak overcost atau overdue.

    Bung Endy bikin perusahaan sendiri? Yang menerapkan XP? Jadi ketua milis xp atau agile indonesia aja. Trus kita temu darat untuk memajukan budaya programming yang baik. Gimana?

    ~ILoveCleanCodesAndAgileDevelopment

  8. By obie on Nov 27, 2007 | Reply

    MAs, Anda kan sering menangani proyek, aQ butuh bantuan nih?? aQ tertarik pada refaktoring database n code, tp aQ bingung krn krng pengalaman nih, jd cuma tahu teori. aQ butuh topik TA dlm hal refaktoring,,,, klo punya,,,Please send to me,,,,,!!??

Post a Comment