Pendahuluan

Pendahuluan mengenai Parameterized Test bisa dilihat di sini.

Kesimpulan dari menggunakan Parameterized Test diatas adalah :

Dengan Parameterized Test , maka :

  • Lebih mudah untuk mengkatogorisasikan jenis kasus di Unit test nya.
  • Lebih mudah mencari test method yang berkaitan.
  • Code nya lebih pendek dan lebih jelas.

Dalam kenyataannya, banyak kondisi yang perlu kita tambahkan parameter untuk unit test nyat tersebut, misalnya :

  • Kita ingin menambahkan satu parameter saja dengan tipe yang sama.
  • Kita ingin menambahkan banyak parameter dengan tipe yang sama.
  • Kita ingin menambahkan banyak parameter dengan tipe yang berbeda.
  • Kita ingin menambahkan banyak parameter dengan tipe Enum.

Contohnya ?



1. Kita ingin menambahkan satu parameter saja dengan tipe yang sama.

Coba kita lihat code ini :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
package com.huzefril.unittest;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class ServiceA {

	public boolean method1(String input1) {

		if (StringUtils.isNotBlank(input1) && (input1.equals("A") || input1.equals("B"))) {
			log.info("Input {} is valid", input1);
			return true;
		}

		return false;
	}
}

Didalamnya kita ingin mengetes untuk inputannya saja yang hanya terdiri dari satu parameter bertipe String yaitu variable input1

Oleh karenanya kita coba untuk membuat Unit Testnya sbb :


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.huzefril.unittest;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.NullAndEmptySource;
import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.InjectMocks;

public class ServiceATest {

	@InjectMocks
	private ServiceA serviceA = new ServiceA();

	@ParameterizedTest
	@NullAndEmptySource
	@ValueSource(strings = {"C","D"})
	public void testInput_False(String input) {
		// call method
		boolean result = serviceA.method1(input);

		// assert
		assertFalse(result);
	}

	@ParameterizedTest
	@ValueSource(strings = {"A","B"})
	public void testInput_True(String input) {
		// call method
		boolean result = serviceA.method1(input);

		// assert
		assertTrue(result);
	}
}

Didalamnya kita menggunakan :

  • NullAndEmptySource , untuk parameter Null dan Empty String untuk tipe parameter String input. Hasilnya adalah false.
  • @ValueSource(strings = {“A”,“B”}) , @ValueSource(strings = {“C”,“D”} , untuk keperluan parameterized test untuk satu parameter saja. Hasilnya adalah true untuk “A” dan “B”, dan false untuk selainnya.

Di code diatas kita mendefinisikan tipe dari parameter yang kita passing, yaitu bertipe strings

Tipe struktur data yang disupport memakai @ValueSource ini antara lain :

  • shorts
  • bytes
  • ints
  • longs
  • floats
  • doubles
  • chars
  • booleans
  • strings
  • classes


2. Kita ingin menambahkan banyak parameter dengan tipe yang sama.


Kembali lagi ke code yang diatas :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
 package com.huzefril.unittest;

 import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Service;

 import lombok.extern.slf4j.Slf4j;

 @Service
 @Slf4j
 public class ServiceA {

 	public boolean method1(String input1) {

 		if (StringUtils.isNotBlank(input1) && (input1.equals("A") || input1.equals("B"))) {
 			log.info("Input is valid");
 			return true;
 		}

 		return false;
 	}
 }
 

Kita sebenarnya bisa membuat Unit Test menjadi lebih singkat, dengan membuat parameter untuk input1, dan parameter untuk hasilnya juga, berupa true/false.

Misalnya :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.huzefril.unittest;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.NullAndEmptySource;
import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.InjectMocks;

public class ServiceATest {

	@InjectMocks
	private ServiceA serviceA = new ServiceA();

	@ParameterizedTest
	@CsvSource({ "null,false", "'',false", "A,true", "B,true", "C,false", "D,false" })
	public void testInput_Success(String input, Boolean result) {
		// call method
		boolean response = serviceA.method1(input);

		// assert
		assertEquals(result, response);
	}
}

Coba lihat, code kita jadi lebih pendek.

Dengan mengkombinasikan parameter untuk input1 dan hasilnya, maka dengan mudah kita menambah kombinasi parameter lainnya.

Dari code diatas, artinya :

  • untuk input “null”, maka ekspektasi hasil dari method nya adalah false.
  • untuk input "", maka ekspektasi hasil dari method nya adalah false.
  • untuk input “A”, maka ekspektasi hasil dari method nya adalah true.
  • untuk input “B”, maka ekspektasi hasil dari method nya adalah true.
  • untuk input “C”, maka ekspektasi hasil dari method nya adalah false.
  • dst

Didalamnya kita menggunakan :

  • CsvSource , untuk membuat banyak parameter dengan tipe yang sama, atau tipe yang bisa otomatis di convert oleh librarynya.
  • dengan CsvSource , maka kita bisa me-listing semua kombinasi antara inputan dengan hasil nya.


3. Kita ingin menambahkan banyak parameter saja dengan tipe yang berbeda.


Kembali lagi ke code yang diatas :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
package com.huzefril.unittest;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class ServiceA {

	public boolean method1(String input1) {

		if (StringUtils.isNotBlank(input1) && (input1.equals("A") || input1.equals("B"))) {
			log.info("Input is valid");
			return true;
		}

		return false;
	}
}

Selain dengan @ValueSource, dan @CsvSource diatas,kita juga bisa membuat parameternya dalam bentuk method.

Kita memakai anotasi @MethodSource.

Contohnya sbb :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.huzefril.unittest;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.stream.Stream;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.mockito.InjectMocks;

public class ServiceATest {

	@InjectMocks
	private ServiceA serviceA = new ServiceA();

	@ParameterizedTest
	@MethodSource("paramArgument1")
	void testInputMethodSource_Success(String input, Boolean result) {
		// call method
		boolean response = serviceA.method1(input);

		// assert
		assertEquals(result, response);
	}

	private static Stream<Arguments> paramArgument1() {
		return Stream.of(
				Arguments.of(null, false),
				Arguments.of("", false),
				Arguments.of("A", true),
				Arguments.of("B", true),
				Arguments.of("C", false),
				Arguments.of("D", false)
				);
	}
}


4. Kita ingin menambahkan banyak parameter saja dengan tipe Enum.


Sebenarnya ini mirip dengan contoh 1 diatas

  1. Kita ingin menambahkan satu parameter saja dengan tipe yang sama.

Tetapi kita ingin membungkusnya dalam objek nya Java berupa Enumeration.

Misalnya kita buat sebuah Enum untuk contoh inputannya, sbb :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
package com.huzefril.unittest;

public enum InputEnum {
	A("A"),
	B("B"),
	C("C"),
	D("D"),
	NULL(null),
	EMPTY("");

	String stringValue;

	InputEnum(String string) {
		this.stringValue = string;
	}

	String getStringValue() {
		return this.stringValue;
	}
}

dan untuk Unit Test nya :


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import static org.junit.jupiter.api.Assertions.assertNotNull;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import org.mockito.InjectMocks;

public class ServiceATest {

	@InjectMocks
	private ServiceA serviceA = new ServiceA();

	@ParameterizedTest
	@EnumSource(InputEnum.class)
	void testInputEnumSource_Success(InputEnum inputEnum) {
		// call method
		boolean response = serviceA.method1(inputEnum.getStringValue());

		// assert
		assertNotNull(response);
	}
}

Maka secara otomatis semua nilai dari Enum diatas akan diiterasi dan dilakukan test terhadap method testInputEnumSource_Success .