Bagian 1. Siklus Test Driven Development

Seperti Kent bilang, tujuan dari contoh ini adalah untuk memperkenalkan anda pada ritme atau siklus dari TDD:

  1. Tambahkan sedikit test.

  2. Jalankan semua test, pastikan tambahan tadi gagal total.

  3. Buat sedikit perubahan.

  4. Jalankan semua test, pastikan kali ini sukses.

  5. Hilangkan duplikasi.

  6. Jalankan semua test, pastikan tidak ada kegagalan karena perubahan tadi.

Multi-Currency Money

Kent memulai dengan sebuah contoh tentang money atau uang. Menjumlahkan satu mata uang dengan mata uang lainnya. Menjumlahkan 10 dolar US dengan 100.000 rupiah. Kebayangkan ribetnya. Nampak sekali kalau mata uang kita nol-nya terlalu banyak.

Berikut ini adalah contoh laporan penjualan dua jenis laptop dengan dua mata uang:

Item Harga per item Jumlah Total
Laptop Tohsiba Rp 5.000.000,00 2 Rp 10.000.000,00
Laptop Sony Vaio $ 550,00 1 $ 550,00
Total 3 XXXXXX??

Perhatikan tanda XXXXX. Tanda ini saya maksudkan sebagai sesuatu yang tidak bisa jumlahkan. Agar bisa dijumlahkan ia harus memilih salah satu jenis mata uang, dolar atau rupiah.

Dari laporan ini, menurut Kent, kita dapat membuat daftar apa yang harus kita kerjakan atau todo-list:

$5 + Rp 10=Rp 9.010 jika $1=Rp 9000
Rp 10 * 2 = Rp 20

Todo list ini akan membuat kita tetap fokus pada persoalan. Ketika kita memulai, kita bold item yang sedang kita kerjakan. Ketika sudah selesai kita cukup dengan mencoret item yang telah kita kerjakan itu. Dan ketika kita tiba-tiba terpikir untuk menambah test yang lain, kita cukup menambahkan ke dalam daftar test.

Persiapan

Baca tulisan saya mengenai persiapan.

Buat folder Fatur.Tdd.Test dibawah folder test. Buat didalamnya file “MoneyFixture.cs”

Buat folder Fatur.Tdd dibawah folder app. Buat didalamnya file “Money.cs”

Jalankan NAnt. Pastikan sukses.

Test Pertama : Perkalian

Dari daftar diatas, mana yang akan kita pilih? Saya akan memilih yang paling mudah terlebih dahulu: perkalian. Mengapa lebih mudah? Penjumlahan melibatkan dua mata uang dan ini lebih rumit karena tentu membutuhkan test-test yang lain lagi.

Ok. Setuju sajalah dengan perkalian. Kita mulai dari mana? Objek apa yang kita butuhkan. Oh, pertanyaan yang sulit..Objek? Kita tidak memulai dengan object, kita memulai dengan test.

Lalu apa yang kita test? Kent mengatakan:

“Pada saat membuat test, bayangkanlah interface dari operasi yang akan kita kerjakan. Lihat seperti apa operasi itu ditengok dari luar.” (ini saya sarikan saja, jangan coba-coba mencarinya di buku).

Anda tahu API kan? Application Program interface. Ketika membuat test bayangkanlah anda sedang bekerja dengan API. Anda sedang berdiri di sisi pengguna API. Dan tentu saja bayangkan juga API itu telah selesai dan sempurna. (ada saatnya kita membuat implemtasi API yang sesungguhnya—sabar, kita sedang berproses.)

Didalam file MoneyFixture.cs saya buat program test seperti berikut ini:

using NUnit.Framework;
namespace Fatur.Tdd {
	[TestFixture]
	public class MoneyFixture {
		[Test]
		public void Multiplication(){
			Rupiah sepuluhRupiah=new Rupiah(10);
			sepuluhRupiah.Times(2);
			Assert.AreEqual(20,sepuluhRupiah.Amount);
		}
	}
}

Saya menggunakan NUnit. Bagaimana caranya? Baca tulisan saya mengenai: “NUnit: dari mana memulai”.

Pertama saya buat object sepuluhRupiah, object ini kemudian saya kalikan 2 dengan memanggil method Times(). Setelah dikali saya berharap amount akan berubah menjadi 20.

Yakin saya. Anda pasti protes. “Jelek sekali design kamu, masak setelah dikali 2 namanya tetap sepuluhRupiah, sedangkan nilainya sudah berubah menjadi 20”

Ok. Saya terima segala macam kritikan, yang pedas-pedas sekalian deh. Tapi tunggu sebentar, TDD adalah proses belajar, ya Anda ya program. Saya berjanji diakhir proses nanti akan ada hasil yang jauh lebih baik dari program diatas. Karenanya TDD juga disebut sebagai alat untuk meningkatkan kualitas program. Protes Anda diatas saya masukkan ke dalam list dan saya berinama: “Efek perkalian terhadap object”. Ada keberatan lagi?

Amount mestinya private sajalah, dia kan data. Data dihide aja. Ok. “Amount harus private”. Ada lagi?

Sepuluh kan integer, bagaimana kalau pecahan? Pembulatan maksudmu? Ya, pembulatan uang. Ok. Saya catat:”Pembulatan uang”. Ada lagi? Tidak.

Jika tidak ada maka to-do list kita bertambah 3:

$5 + Rp 10=Rp 9.010 jika $1=Rp 9000

Rp 10 * 2 = Rp 20

Efek perkalian terhadap object?

Amount harus private?

Pembulatan uang?

Wah, satu saja belum selesai kok sudah nambah ya? Kemaruk amat. Semua ide yang muncul di kepala catat saja. Nanti kalau ternyata tidak berguna ya hapus saja. Gampangkan. Jangan buat hidup yang sudah sulit menjadi semakin sulit.

Program kita diatas ternyata dikompile pun belum bisa. Pesan yang muncul: “tidak ditemukan kelas Rupiah”!

Untuk menghilangkan pesan ini cukup kita buat class Rupiah di file Money.cs:

namespace Fatur.Tdd {
	public class Rupiah{
	}
}

Pesan diatas memang menghilang, tetapi lantas muncul 3 pesan lagi:

  1. Tidak ada konstruktor.

  2. Tidak ada method Times().

  3. Tidak ada property Amount.

Pesan-pesan yang masuk akal. Mari kita hapus ke 3 pesan diatas sekaligus.

public class Rupiah{
	public Rupiah(int amount){
	}
}

Konstruktor kita tambahkan. Kita tidak melakukan apa-apa didalam konstruktor. Hanya memenuhi apa yang diminta kompiler. Yang penting bisa dikompile, itu tujuan kita. Satu pesan error menghilang, tinggal dua lagi.

public class Rupiah{
	public Rupiah(int amount){
	}
	public void Times(int multiplier){
	}
}

Method Times() kita tambahkan. Sekali lagi, kita tidak menambahkan apa-apa. Sekali lagi yang penting bisa dikompile. Satu pesan kesalahan lagi.

public class Rupiah{
	public Rupiah(int amount){
	}
	public void Times(int multiplier){
	}
	public int Amount{
		get {
			return 0;
		}
	}
}

Horeeee! Sekarang kita bisa menjalankan test.

fatur@fatur-laptop:/media/Data/Fatur.Data/workspace/project/tdd$ nant run-tests

BUILD FAILED !!

Bukan, ini bukan gagal build. Ini pesan kalau test yang kita jalankan tidak memenuhi apa yang kita inginkan. Buka folder build, buka file Fatur.Tdd.Test.dll-result.xml. Pesan kesalahan:

expected: <20>

but was: <0>

NUnit telah menjalankan test kita. Ia melaporkan bahwa hasilnya 0 bukan 20. Test kita gagal! Sedih?

Tidak. Jangan sedih. Dalam TDD, kesalahan adalah sebuah perkembangan, sebuah pertumbuhan, sebuah kemajuan. Itu lebih baik dari sekedar tahu bahwa apa yang kita buat salah. Cara kita membuat program telah berubah dari “beri saya program multi-currency” menjadi “buat test ini jalan, dan selesaikan test yang tersisa”. Lebih mudah. Lebih kecil titik permasalahannya. Dan pasti kita bisa menyelesaikannya.

Ingat sekali lagi tujuan kita bukan memberi jawaban yang benar. Tetapi hanya agar test yang kita buat berjalan. Itu saja tidak lebih. Simpel dan mudah.

Dan untuk itu kita hanya cukup mengganti nilai kembalian property dari 0 menjadi 20 (dua puluh). Itu saja dan test kita SUCCESS!

public int Amount{
	get {
		return 20;
	}
}

Selesai? Belum. Siklus kita belum selesai. Perhatikan baik-baik siklus berikut ini:

  1. Tambahkan sedikit test.

  2. Jalankan semua test, pastikan tambahan tadi gagal total.

  3. Buat sedikit perubahan.

  4. Jalankan semua test, pastikan kali ini sukses.

  5. Hilangkan duplikasi.

  6. Jalankan semua test, pastikan tidak ada kegagalan karena perubahan tadi.

Sejauh ini dari 6 langkah siklus TDD, kita telah menjalankan langkah 1 sampai 4. Sekarang kita akan melakaukan langkah 5 dan 6.

Langkah 5 berbicara mengenai “duplikasi”, sesuatu yang ganda. Sesuatu yang sudah ada kita adakan lagi. Double. Anda tahu dimana duplikasi yang muncul di program kita?

Ada dua macam duplikasi. Pertama, duplikasi code. Kalau kita melakukan copy-paste, sudah pasti yang muncul adalah duplikasi. Duplikasi code sangat mudah dikenali.

Duplikasi kedua yaitu duplikasi data. Data di dalam test dan data di dalam code. Dalam kasus kita kali ini, duplikasi yang muncul adalah duplikasi data. Perhatikan test dan code berikut ini:

[Test]
public void Multiplication(){
	Rupiah sepuluhRupiah=new Rupiah(10);
	sepuluhRupiah.Times(2);
	Assert.AreEqual(20,sepuluhRupiah.Amount);
}

dan

public int Amount{
	get {
		return 10*2;
	}
}

Sudah terlihat duplikasinya? Kalau belum, code saya ubah menjadi:

public int Amount{
	get {
			return 10*2;
		}
	}

Cukup jelas bukan? Di dalam test ada nilai 10 dan 2 begitu juga di dalam code.

Kita telah melakukan perubahan sedikit. Test kembali saya jalankan dan hasilnya tetap success.

Perhatikan, langkah kita kecil bahkan sangat kecil. Apakah harus seperti itu? Tidak. Kent bilang, “TDD bukan tentang membuat program dengan langkah-langkah kecil, tetapi tentang apakah bisa mengambil langkah-langkah kecil”. Jika langkah kecil itu sudah cukup memberikan kita arah yang benar, maka langkah kecil itu cukuplah. Pertanyaannya: langkah kecil itu seperti apa, atau paling tidak adakah ukurannya? Kent tidak menyebutkan aturan yang pasti, kita harus mencari sendiri ukuran-ukuran itu dengan banyak mencoba. Sebab ketika kita bisa melakukan langkah-langkah yang sangat kecil kita bisa menentukan besarnya langkah yang sesuai untuk kita. Jika kita hanya bisa melakukan dengan langkah-langkah besar, kita tidak akan pernah tahu bahwa langkah kecil pun sebenarnya cukup.

Kembali lagi ke duplikasi. Darimana datangnya nilai 10? Nilai ini datangnya dari konstruktor, bukan. Nilai ini harus kita simpan sebagai variabel private didalam object,

public class Rupiah{
	private int m_amount;
	public Rupiah(int amount){
		this.m_amount=amount;
	}
	...
}

Lalu variabel m_amount ini kita gunakan untuk mengganti nilai 10,

public class Rupiah{
	private int m_amount;
	...
	public int Amount{
		get {
			return this.m_amount*2;
		}
	}
}

Test kembali saya jalankan dan hasilnya tetap success.

Nilai 2 datang darimana? Nilai ini datang dari method Times().

public class Rupiah{
	...
	public void Times(int multiplier){
		this.m_amount=this.m_amount*multiplier;
	}
	public int Amount{
		get {
			return this.m_amount;
		}
	}
}

Perhatikan juga, property Amount hanya mereturn m_amount tanpa harus melakukan perkalian seperti sebelumnya. Perkalian ini saya pindah ke dalam method Times().

Test kembali saya jalankan dan hasilnya tetap success.

Sekarang muncul duplikasi didalam code. Dalam C#/mono, perkalian bisa digantikan dengan operator *=pengali. Sehingga code this.m_amount=this.m_amount*multiplier bisa dianggap sebagai duplikasi dan kita ubah menjadi,

public class Rupiah{
	public void Times(int multiplier){
		this.m_amount *=multiplier;
	}
}

Test kembali saya jalankan dan hasilnya tetap success.

Perhatikan, di langkah 5 dan 6 ini saya mengulangnya sampai 4 kali melalaui langkah kecil-kecil.

$5 + Rp 10=Rp 9.010 jika $1=Rp 9000

Rp 10 * 2 = Rp 20

Efek perkalian terhadap object?

Amount harus private?

Pembulatan uang?

Sementara, test ini kita anggap selesai. Sebagai tanda kita cukup mencoret dari daftar test (to-do list).

Sebelum kita melanjutkan test, kita review apa saja yang telah kita lakukan:

  • Kita telah membuat daftar test sejauh yang kita tahu sedemikian hingga program bisa berjalan.

  • Buat cerita bagaimana program berjalan dalam bentuk code test.

  • Buat test sedemikian hingga bisa dikompile.

  • Buat test berjalan/sukses.

  • Perlahan tapi pasti, kita telah membuat program berjalan dengan mengubah beberapa konstanta menjadi variabel.

  • Kita tidak membuat daftar test (todo-list) seluruhnya diawal, tetapi menambahkan satu demi satu begitu terpikir bersamaan pada saat membuat program.

Iklan

There are no comments on this post.

Tinggalkan Balasan

Isikan data di bawah atau klik salah satu ikon untuk log in:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s

%d blogger menyukai ini: