Cara Suudzon di JUnit
Halo semua! Pada minggu ke 2–3 sprint 1 ini, saya memiliki task untuk membuat model dari transaksi produk. Dalam pembuatan model itu tentu tidak lepas dari pembuatan tesnya kan. Kita semua tahu bahwa unit testing adalah salah satu cara terbaik untuk mengeliminasi bug-bug kecil yang mungkin terjadi saat proses pengerjaan suatu proyek. Unit testing yang baik selalu terdiri atas positive dan negative testing. Positive testing digunakan untuk memastikan bahwa program kita berjalan dengan baik untuk input yang sesuai ekspektasi. Sedangkan, negative testing memastikan program berjalan dengan baik untuk input yang secara desain invalid, atau dengan kata lain kita suudzon pada user dan bagian lain pada program, jangan-jangan mereka mau memberi nilai invalid pada bagian program ini. Pada blog post kali ini, kita akan membahas negative testing pada java dengan JUnit.
Untuk memudahkan pembahasan, kita akan mengambil suatu objek model pada java sebagai acuan. Misalkan kita memiliki desain objek sebagai berikut.
public class TestClass {
private Date date;
public TestClass(Date date) {
//TODO: implement
}
public Date getDate() {
//TODO: implement
}
public Date setDate() {
//TODO: implement
}
}
Ambil asumsi bahwa kita memiliki restriksi atribut date tidak boleh null. Berarti, positive testing kita tentu saja mudah, kita bisa cek constructor dan setter dengan nilai date yang tidak null dan kita cek bahwa atribut tersebut sesuai dengan yang diberikan, misalnya dengan code sebagai berikut:
@Test
public void testValidConstructor() {
Date current = new Date();
TestClass temp = new TestClass(current);
assertTrue(temp.getDate().equals(current));
}@Test
public void testValidSetter() {
Date current = new Date();
Date notCurrent = new Date(0);
TestClass temp = new TestClass(current);
temp.setDate(notCurrent);
assertFalse(temp.getDate().equals(current));
assertTrue(temp.getDate().equals(notCurrent));
}
Dimana kedua test di atas akan benar selama kita tidak menjalankan test pada Unix epoch.
Namun, negative testing tentu lebih sulit untuk dilakukan. Sebelumnya, kita harus menjawab secara desain bagaimana kita akan menghandle masukan null untuk atribut date pada setter dan constructor. Secara umum ada tiga opsi yang dapat kita lakukan:
1. Membiarkan nilai null. Bagian program yang lain yang akan merestriksi.
2. Memberi suatu default value.
3. Melempar exception.
Untuk kasus 1, berarti tidak ada restriksi pada kelas kita, maka tidak ada negative testing, karena tidak ada input invalid.
Untuk kasus 2, kita dapat melakukan pengecekan semudah positive testing. Misalkan default value adalah waktu pada Unix epoch:
@Test
public void testInvalidConstructor() {
TestClass temp = new TestClass(null);
assertTrue(temp.getDate().equals(new Date(0)));
}
Untuk kasus 3, pengecekan menjadi cukup sulit. Kita harus menghandle exception pada unit testing kita. Jika kita tidak terlalu tahu caranya, secara intuisi kita akan melakukan seperti ini:
@Test
public void testInvalidConstructor() {
boolean isExceptionThrown = false;
try {
TestClass temp = new TestClass(null);
} catch(IllegalArgumentException e) {
isExceptionThrown = true;
}
assertTrue(isExceptionThrown);
}
Namun, terlalu banyak logic yang digunakan pada unit test kita, padahal unit test sebaiknya sederhana sehingga kebeneran unit test tidak perlu dipertanyakan. Jadi, bagaimana cara yang baik?
Seperti dapat dilihat pada link ini, ada atribut opsional “expected” pada annotation test JUnit yang meminta argumen berupa suatu kelas Throwable. Dengan menggunakan atribut ini, tes yang dijalankan hanya dapat sukses jika saat metode testing dijalankan terdapat Throwable yang diminta. Dengan menggunakan parameter ini, kita dapat mengganti code sebelumnya dengan sangat mudah menjadi sebaai berikut:
@Test(expected = IllegalArgumentException.class)
public void testInvalidConstructor() {
new TestClass(null);
}
Mudah sekali bukan? Dengan menggunakan ini, kita dapat menjalankan Negative Testing dengan sangat mudah. So, aim for that 100% coverage!