Em um outro post, falamos um pouco sobre a utilização do FSCheck para criação de testes de propriedade usando C#. Mostrei os primeiros passos com o FSCheck, e a criação de testes de propriedade bem simples onde nosso teste dependia de um valor _uint p_ara representar uma porcentagem, porém esse tipo de valor pode ser maior do que 100, o que no nosso caso se encaixa muito bem dado que nossa porcentagem seria somente de 0 a 100.
Nesse post iremos nos aprofundar um pouco mais na criação de parâmetros customizáveis, limitando os valores, criando alguns mais específicos e descritivos.
Contexto
No primeiro post que fiz sobre o FSCheck mostrei um contexto de uma aplicação de FlashCards onde testávamos se um cartão tinha sua porcentagem de dificuldade diminuída caso o usuário acertasse a reposta ou se aumentava a dificuldade caso o usuário errasse. O código do nosso exemplo é esse aqui:
[Property]
public Property DeveDiminuirDificuldadeQuandoAcertarAResposta(int porcentagem)
{
var calculadora = new CalculadoraDeDificuldade();
var cartão = new Cartão("qlqr pergunta", porcentagem);
var novoCartão = calculadora.AjustaDificuldade(cartão, true);
return (novoCartão.Porcentagem < porcentagem).ToProperty();
}
A questão com esse teste é que o valor de porcentagem está variando entre todos os possíveis para uma variável do tipo int, e a nossa propriedade só é válida quando o valor da porcentagem for entre 0 e 100. O FsCheck possui o método When que faz exatamente isso, portanto podemos alterar a criação da nossa propriedade para que fique assim:
return (novoCartão.Porcentagem < porcentagem)
.ToProperty()
.When(porcentagem != 0 && porcentagem < 100);
Utilizando o método When conseguimos limitar o valor do parâmetro porcentagem que será válido para a nossa Propriedade, porém agora todo teste que dependa desse valor teremos que adicionar esse código. O que precisamos é que o FSCheck saiba gerar corretamente os valores, e para isso ele disponibiliza uma maneira de criar os nossos próprios geradores de valores.
Gerando valores customizáveis
Para criar esse valores customizaveis iremos criar uma classe para agrupar os geradores, e esses geradores serão métodos estáticos que retornam um Arbitrary do valor que quer gerar.
O nome do método podemos colocar algo que deixe explícito o retorno.
No nosso caso o tipo que usamos é int, iremos criar um método estatico que irá retornar um Arbitrary de int e iremos dar o nome de Porcentagem.
public class Tipos
{
public static Arbitrary<int> Porcentagem() =>
Arb.Default.Int32().Generator.
Where(x => x > 0 && x <= 100).ToArbitrary();
}
Olhando a implementação acima veja que utilizamos o próprio gerador de int da biblioteca Arb.Default.Int32().Generator e depois usamos um Where para filtrar o intervalo de valores que queremos. E para retornar um Arbitrary basta chamar o método ToArbitrary.
Agora que criamos esse gerador, precisamos fazer indicar para o nosso teste que deve utilizar essa classe como fonte. Conseguimos fazer isso apenas alterando o atributo Property:
[Property(Arbitrary = new[] {typeof(Tipos)})]
Com isso quando o nosso teste solicita uma entrada to tipo int, ele acha o nosso gerador e chama ele ao invés do padrão, com isso nosso código não precisa mais lidar com o tratamento do valor e podemos remover o When que tínhamos colocado.
Olhando nosso código, utilizamos a porcentagem para criar nosso objeto Cartão e usamos ele para fazer o teste. E se, ao invés de receber a porcentagem, nós recebessemos um objeto de Cartão já pronto?
Criando nosso Cartão
Para criar um novo gerador, precisamos alterar nossa classe Tipos, e adicionar agora um novo método que retorne um Arbitrary de Cartão. Nele podemos utilizar o gerador de Porcentagem que criamos e mapear para um Cartão. Veja como fica a implementação:
public static Arbitrary<Cartão> Cartão() =>
Porcentagem().Generator
.Select(porcentagem => new Cartão(Arb.Default.String()
.Generator
.Sample(20, 1)
.Single(),
porcentagem))
.ToArbitrary();
Veja que estamos mapeando uma porcentagem para o nosso Cartão, e utilizamos outro gerador padrão do FSCheck para construir a descrição do cartão de maneira automática também. Agora basta alterar nosso teste para receber um Cartão
[Property(Arbitrary = new[] {typeof(Tipos)})]
public Property DeveDiminuirDificuldadeQuandoAcertarAResposta3(Cartão cartão)
{
var calculadora = new CalculadoraDeDificuldade();
var novoCartão = calculadora.AjustaDificuldade(cartão, true);
return (novoCartão.Porcentagem < cartão.Porcentagem).ToProperty();
}
Com isso conseguimos construir qualquer objeto nosso com as restrições que precisamos para determinada propriedade, e deixar nosso teste simples e descritivo.
Podemos também criar classes que representem estados dos nossos objetos, como por exemplo um _ CartãoComPorcentagemAcimaDe80 _ que estende o Cartão. Dá para viajar nisso, mas falaremos disso em outro post.
Se quiser dar uma olhada no código, ele está no meu github: fscheck-examples
Eai, o que achou da utilização de geradores customizáveis? Tem dúvidas? Já usou?
Deixe um comentário ?
Abraços
Imagem usada no post Orsolya Vékony em Unsplash
O post FSCheck: Gerando valores customizados para seu teste de propriedade apareceu primeiro em High5Devs.
Top comments (0)