Unit Testing


Pertama-tama mendengar unit testing, langsung kepikiran kenapa capek2 buat code program untuk ngetest aplikasi yang di develop. Buang2 waktu sebab aplikasi bisa di test manual melalui user interface aplikasi. Isi data2 yang di form aplikasi, klik tombol submit, cek apakah ada error, atau data masuk ke database.

Lama kelamaan sejalan dengan waktu aku baru sadar kalau cara itu kurang efektif. Basically developer harus mengetest code yang di develop setiap kali ada perubahaan. Untuk menjamin code yang di tulisnya berjalan dengan benar.  Akan membuang banyak waktu jika tiap kali ada perubahan harus melakukan berulang2  isi data2 yang di perlukan user interface aplikasi, submit, cek apakah ada error atau mengecek apakah data sudah masuk di database.  Seratus kali perubahaan setarus kali test manual (input data) di lakukan. Programmer membangun aplikasi untuk membantu manusia mengautomatisasi pekerjaan mereka. Jadi kenapa kita tidak membantu diri kita sendiri mengautomatisasi pekerjaan dalam hal testing aplikasi ?

Sebelum membuat Unit Test developer terlebih dahulu membuat acceptance test yang merupakan spesifikasi test untuk tiap unit. Misalkan unit RegistrationService, pekerjaan unit ini memproses data registrasi user, dan menyimpan data registrasi ke database. Namun ada constraint, nama tidak boleh sama dengan existing data begitu juga dengan email. Jadi sepsifikasi test untuk unit RegistrationService kira2 seperti ini:

1. should_save_registration_data_when_valid_data_submited()
2. should_throw_UserNameExistsException_when_existing_user_name_submited()
3. should_throw_EmailExistsExeception_when_existing_email_submited()

Aceptance test diimplementasikan sesuai dengan ekspektasi yang diharapkan. Untuk acceptance test pertama ekspektasinya data user masuk ke database, acceptance test kedua mendapatkan throw UserNameExistsException, dan yang terakhir medaapatkan EmailExistsExpcation. Ekspektasi dalam unit test biasanya menggunakan assert atau expect.  Ekspektasi di tiap implementasi acceptance test menyatakan berhasil atau tidak nya hasil eksekusi unit test.

Contohnya kira2 seperti ini:

public class RegistrationServiceTest {
	IRegistrationService registrationService;
	IUserService userService;
	RegistrationCommand validCommand;
	RegistrationCommand invalidUserCommand;
	RegistrationCommand invalidEmailcommand;

	@Before
	setup() {
		registrationService = new RegistratioService();
		IEmailService emailService = EasyMock.CreateMock(IEmailService.class);
                //create mock object using EasyMock
		registrationService.setEmailService(emailService);

		validCommand = RegistrationCommand();
		validCommand.setUserName("my_name");
		validCommand.setPassword("my_password");
		validCommand.setEmail("my_email@host.com");

		invalidUserCommand = RegistrationCommand();
		invalidUserCommand.setUserName("exists");
		invalidUserCommand.setPassword("my_password");
		invalidUserCommand.setEmail("my_email@host.com");

		invalidEmailcommand = RegistrationCommand();
		invalidEmailcommand.setUserName("my_name");
		invalidEmailcommand.setPassword("my_password");
		invalidEmailcommand.setEmail("exists@host.com");
	}

	should_save_registration_data_when_valid_data_submited() {
		registrationService.register(validCommand);
		User user = userService.findByUserName(validCommand.getUserName);
		assertNotNull(user) //user masuk ke database
	}

	@expect(UserNameExistsException.class)
	should_throw_UserNameExistsException_when_existing_user_name_submited() {
		registrationService.register(invalidUserCommand);
	}

	@expect(EmailExistsExeception.class);
	should_throw_EmailExistsExeception_when_existing_email_submited() {
		registrationService.register(command);
	}

	@after
	tearDown() {
		userService.removeUser(validCommand.getUserName);
	}

}

Menggunakan unit test developer di automasi untuk mengetest aplikasi setiap kali perubahaan. Tanpa harus mengisi input data berulang-ulang.

Unit test yang benar itu tidak boleh terlalu banyak berhubungan dengan unit lain. Contohnya saat registrasi berhasil, email notifikasi dikirimkan ke user.  Jika unit test melibatkat eksekusi send email akan membuat eksekusi unit test semakin lama  Karena saat mengirimkan email butuh koneksi ke email server,authentikasi, dan send email. Oleh karena itu send email sebaiknya tidak di ikutkan.

Contoh code Registration service

RegistrationService implements IRegistrationService {
	IEmailService emailService;
	IUserDao userDao;

	public void setEmailService(IEmailService emailService) {
		this.emailService = emailService;
	}

	public void IUserDao(IUserDao userDao) {
		this.userDao = userDao;
	}

	public void register(RegistrationCommand command) {
		//logic registrasi

		//send email after registration succesfully executed
		emailService.send(command.getEmail(), "user registered successfully");
	}
}

Tapi Email service harus tetap di set di registration service. Kalau tidak akan menyebabkan NullPointerException saat eksekusi emailService.send(). Caranya membuat Mock Object/objek jadi-jadian lalu di set ke registrationService.

       @Before
	setup() {
		registrationService = new RegistratioService();
		IEmailService emailService = EasyMock.CreateMock(IEmailService.class);
		registrationService.setEmailService(emailService);
	}

Disini pattern Programing To Interface itu digunakan, selain mengurangi dependency antar class juga mempermudah developer untuk tidak mengikut sertakan unit infrastruktur ke unit test dengan membuat mock object terhadap unti infrastruktur itu.

Kesimpulan:
Unit test mengutomatisasi pekerjaan developer untuk mengetest setiap kali ada perubahan code yang dia tulis.
Acceptance test merupakan spesifikasi testing untuk tiap unit, di sini di sepsifikasikan kemungkinan2 yang terjadi di unit itu dan di test.
Tiap implementasi acceptance test harus memiliki ekspektasi untuk menyatakan bahwa eksekusi unit test berhasil atau tidak.
Jika ada beberapa unit infrastruktur yang dependent ke unit yang akan di test,sebaiknya unit tersebut di mock saja agar waktu eksekusi unit test lebih cepat.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s