Você conhece testes parametrizados?
É um comportamento comum refatorar o código principal da aplicação para deixar mais legível durante o desenvolvimento do software. Mas e códigos de testes você tem o mesmo cuidado?
Neste artigo, eu quero mostrar uma forma de escrever testes reduzindo o número de linhas e assim sendo mais produtivo fazendo o uso de testes parametrizados.
Os exemplos a seguir serão com Junit5. Para o funcionamento adequado é necessário a instalar a depêndencia junit-jupiter-params.
Criei um simples código onde o objetivo é apenas executar operações matemáticas com dois números.
public class Calculator {
private int x;
private int y;
private String operation;
public Calculator (int x, int y, String operation) {
this.x = x;
this.y = y;
this.operation = operation;
}
public int calculate() {
switch (this.operation) {
case "add":
return x + y;
case "subtract":
return x - y;
case "multiply":
return x * y;
case "divide":
return x / y;
default:
return 0;
}
}
}
O exemplo acima não tem mistério. Recebe x
, y
e de acordo com a operação o resultado será retornado. Se a operação é de desconhecida, o resutado será zero.
Testar o código sem testes parametrizados geraria pelo menos cinco métodos e um monte de linhas como estas:
public class CalculatorTest {
@Test
void mustTestAddition() {
// given
Calculator calculator = new Calculator(10, 2, "add");
// when
int result = calculator.calculate();
// then
Assertions.assertEquals(result, 12;
}
@Test
void mustTestSubtraction() {
// given
Calculator calculator = new Calculator(10, 2, "subtract");
// when
int result = calculator.calculate();
// then
Assertions.assertEquals(result, 8);
}
@Test
void mustTestMultiplication() {
// given
Calculator calculator = new Calculator(10, 2, "multiply");
// when
int result = calculator.calculate();
// then
Assertions.assertEquals(result, 20);
}
@Test
void mustTestDivision() {
// given
Calculator calculator = new Calculator(10, 2, "divide");
// when
int result = calculator.calculate();
// then
Assertions.assertEquals(result, 5);
}
@Test
void mustTestInvalidOperation() {
// given
Calculator calculator = new Calculator(10, 2, "any");
// when
int result = calculator.calculate();
// then
Assertions.assertEquals(result, 0);
}
}
Resumindo seria um teste para cada operação. Agora veja como fica quando usamos testes parametrizados.
public class CalculatorTest {
@ParameterizedTest
@CsvSource({
"10,2,add,12",
"10,2,subtract,8",
"10,2,multiply,20",
"10,2,divide,5",
"10,2,any,0"
})
void mustTestCalculatorOperations(int x, int y, String operation, int expectedResult) {
// given
Calculator calculator = new Calculator(x, y, operation);
// when
int result = calculator.calculate();
// then
Assertions.assertEquals(result, expectedResult);
}
}
É só adicionar a anotação @ParameterizedTest
, definir os cenários dentro de @CsvSource
seguindo a sequência de parâmetros que está declarada no método.
Apesar de ser um texto simples, eu acho que o objetivo foi cumprido. Mas os testes parametrizados tem várias formas de serem executados. Se você quiser se aprofundar mais, eu realmente recomendo o Guia de testes automatizados no Junit5.
Testes parametrizados
Java
Junit
Discussion and feedback