Exemplo de teste de propriedade com Vavr
1. Visão geral
Neste artigo, examinaremos o conceito deProperty Testing e sua implementação na bibliotecavavr-test.
OProperty based testing (PBT) nos permite especificar o comportamento de alto nível de um programa em relação às invariantes às quais ele deve aderir.
2. O que é teste de propriedade?
Uma propriedade é a combinação de um invariante com uminput values generator. Para cada valor gerado, a invariante é tratada como um predicado e verificada se produz verdadeiro ou falso para esse valor.
Assim que houver um valor que produz falso, é dito que a propriedade é falsificada e a verificação é abortada. Se uma propriedade não puder ser invalidada após uma quantidade específica de dados de amostra, presume-se que a propriedade seja satisfeita.
Graças a esse comportamento, nosso teste falha rapidamente se uma condição não for satisfeita sem a realização de um trabalho desnecessário.
3. Dependência do Maven
Primeiro, precisamos adicionar uma dependência Maven à bibliotecavavr-test:
io.vavr
jvavr-test
${vavr.test.version}
2.0.5
4. Escrevendo testes baseados em propriedades
Vamos considerar uma função que retorna um fluxo de strings. É um fluxo infinito de 0 para cima que mapeia números para as seqüências de caracteres com base na regra simples. Estamos usando aqui um recurso interessante do Vavr chamadoPattern Matching:
private static Predicate divisibleByTwo = i -> i % 2 == 0;
private static Predicate divisibleByFive = i -> i % 5 == 0;
private Stream stringsSupplier() {
return Stream.from(0).map(i -> Match(i).of(
Case($(divisibleByFive.and(divisibleByTwo)), "DividedByTwoAndFiveWithoutRemainder"),
Case($(divisibleByFive), "DividedByFiveWithoutRemainder"),
Case($(divisibleByTwo), "DividedByTwoWithoutRemainder"),
Case($(), "")));
}
Escrever o teste de unidade para tal método estará sujeito a erros porque há uma grande probabilidade de esquecermos alguns casos extremos e basicamente não cobrirmos todos os cenários possíveis.
Felizmente, podemos escrever um teste baseado em propriedades que cubra todos os casos extremos para nós. Primeiro, precisamos definir que tipo de números deve ser uma entrada para o nosso teste:
Arbitrary multiplesOf2 = Arbitrary.integer()
.filter(i -> i > 0)
.filter(i -> i % 2 == 0 && i % 5 != 0);
Especificamos que o número de entrada precisa atender a duas condições - precisa ser maior que zero e precisa ser divisível por duas sem restante, mas não por cinco.
Em seguida, precisamos definir uma condição que verifique se uma função testada retorna o valor adequado para o argumento fornecido:
CheckedFunction1 mustEquals
= i -> stringsSupplier().get(i).equals("DividedByTwoWithoutRemainder");
Para iniciar um teste baseado em propriedade, precisamos usar a classeProperty:
CheckResult result = Property
.def("Every second element must equal to DividedByTwoWithoutRemainder")
.forAll(multiplesOf2)
.suchThat(mustEquals)
.check(10_000, 100);
result.assertIsSatisfied();
Estamos especificando que, para todos os números inteiros arbitrários múltiplos de 2, o predicadomustEquals deve ser satisfeito. O métodocheck() assume o tamanho de uma entrada gerada e o número de vezes que este teste será executado.
Podemos escrever rapidamente outro teste que verificará se a funçãostringsSupplier() retorna umDividedByTwoAndFiveWithoutRemainder string para cada número de entrada que é divisível por dois e cinco sem o resto.
O fornecedorArbitrary eCheckedFunction precisam ser alterados:
Arbitrary multiplesOf5 = Arbitrary.integer()
.filter(i -> i > 0)
.filter(i -> i % 5 == 0 && i % 2 == 0);
CheckedFunction1 mustEquals
= i -> stringsSupplier().get(i).endsWith("DividedByTwoAndFiveWithoutRemainder");
Em seguida, podemos executar o teste baseado em propriedades para mil iterações:
Property.def("Every fifth element must equal to DividedByTwoAndFiveWithoutRemainder")
.forAll(multiplesOf5)
.suchThat(mustEquals)
.check(10_000, 1_000)
.assertIsSatisfied();
5. Conclusão
Neste artigo rápido, vimos o conceito de teste baseado em propriedades.
Criamos testes usando a biblioteca vavr-test; usamos as classesArbitrary, CheckedFunction,eProperty para definir o teste baseado em propriedade usandovavr-test.
A implementação de todos esses exemplos e trechos de código pode ser encontradaover on GitHub - este é um projeto Maven, portanto, deve ser fácil de importar e executar como está.