Escrevendo validação e testes unitários em .NET usando o ChatGPT
Muito se discute sobre ele, muitos estão com medo, mas enquanto isso, que tal aproveitá-lo como uma ferramenta a extrair tudo que tem à oferecer ?
Então neste artigo, vou demonstrar como podemos extrair o máximo da ferramenta e garantir muito mais produtividade em nossas tarefas de programação, vou tratar hoje de validação de entidades e criação de testes unitários.
Tudo depende de como você pede, e o que você pede para que a ferramenta lhe dê soluções utilizáveis.
Vou fazer o seguinte pedido:
“Crie uma classe em C# para um cadastro de produto, contendo os seguintes campos: Id (chave primária) do tipo inteiro, Descricao string 50 caracteres, Unidade de Medida (deve ser do tipo enumerador com os seguintes valores possíveis: KG, CX, DZ, MT, TON, UN), Valor de Custo do tipo decimal, com no máximo 3 decimais, Margem de Lucro do tipo decimal, com no máximo 3 decimais, Valor de Venda do tipo decimal com 3 casas decimais, Data da Inclusão, Data da Alteração, Ativo um campo do tipo booleano. Considerar que os nomes das propriedades não devem ter caracteres especiais, elas serão públicas e terão gets e sets.”
Este será o resultado
E ainda vem com uma explicação básica:
Ok, agora vou pedir para refatorar o código, dado que os DateTime precisam ser nullable.
Pronto, classes criadas, vamos para as validações, vou solicitar a seguinte regra:
“Crie uma classe que faça a validação da classe produto com as seguintes regras: O campo Descricao não pode ter mais de 50 caracteres, o campo ValorCusto não pode ser maior que o campo ValorVenda, o campo valorVenda não pode ser menor que o campo valorCusto, utilize a biblioteca FluentValidation para fazer a validação”
A resposta foi o código abaixo, vou colar como código, dado que extrapola a largura da imagem:
using FluentValidation;
public class ProdutoValidator : AbstractValidator<Produto>
{
public ProdutoValidator()
{
RuleFor(p => p.Descricao)
.NotEmpty().WithMessage("A descrição é obrigatória.")
.MaximumLength(50).WithMessage("A descrição não pode ter mais de 50 caracteres.");
RuleFor(p => p.ValorCusto)
.LessThanOrEqualTo(p => p.ValorVenda).WithMessage("O valor de custo não pode ser maior que o valor de venda.");
RuleFor(p => p.ValorVenda)
.GreaterThanOrEqualTo(p => p.ValorCusto).WithMessage("O valor de venda não pode ser menor que o valor de custo.");
}
}
Porém eu não gostei que as mensagens de erro estão dentro do método, vou pedir mudanças:
“poderia reescrever a classe de validação, fazendo com que as mensagens de erro estejam numa classe estática e apenas haja a referência para esta dentro do ProdutoValidator ?”
using FluentValidation;
using System;
public class ProdutoValidator : AbstractValidator<Produto>
{
public ProdutoValidator()
{
RuleFor(p => p.Descricao)
.NotEmpty().WithMessage(MensagensDeErro.DescricaoObrigatoria)
.MaximumLength(50).WithMessage(MensagensDeErro.DescricaoTamanhoMaximo);
RuleFor(p => p.ValorCusto)
.LessThanOrEqualTo(p => p.ValorVenda).WithMessage(MensagensDeErro.ValorCustoMaiorQueValorVenda);
RuleFor(p => p.ValorVenda)
.GreaterThanOrEqualTo(p => p.ValorCusto).WithMessage(MensagensDeErro.ValorVendaMenorQueValorCusto);
}
public static class MensagensDeErro
{
public static string DescricaoObrigatoria => "A descrição é obrigatória.";
public static string DescricaoTamanhoMaximo => "A descrição não pode ter mais de 50 caracteres.";
public static string ValorCustoMaiorQueValorVenda => "O valor de custo não pode ser maior que o valor de venda.";
public static string ValorVendaMenorQueValorCusto => "O valor de venda não pode ser menor que o valor de custo.";
}
}
Pronto, agora parece estar tudo ok, vamos então criar testes de unidade ?
“você poderia criar testes de unidade, utilizando a biblioteca xUnit fazendo testes para caso de sucesso ou insucesso de cada propriedade, utilizando [Theory] com pelo menos 3 valores para cada teste ?”
using FluentValidation.TestHelper;
using Xunit;
public class ProdutoValidatorTests
{
private readonly ProdutoValidator validator;
public ProdutoValidatorTests()
{
validator = new ProdutoValidator();
}
[Theory]
[InlineData("Produto de Teste")]
[InlineData("12345678901234567890123456789012345678901234567890")]
public void Descricao_Valida(string descricao)
{
validator.ShouldNotHaveValidationErrorFor(p => p.Descricao, descricao);
}
[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData("123456789012345678901234567890123456789012345678901")]
public void Descricao_Invalida(string descricao)
{
validator.ShouldHaveValidationErrorFor(p => p.Descricao, descricao);
}
[Theory]
[InlineData(1.00, 2.00)]
[InlineData(1.50, 2.50)]
[InlineData(100.00, 200.00)]
public void ValorCusto_Valido(decimal valorCusto, decimal valorVenda)
{
var produto = new Produto { ValorCusto = valorCusto, ValorVenda = valorVenda };
validator.ShouldNotHaveValidationErrorFor(p => p.ValorCusto, produto);
}
[Theory]
[InlineData(2.00, 1.00)]
[InlineData(2.50, 1.50)]
[InlineData(200.00, 100.00)]
public void ValorCusto_Invalido(decimal valorCusto, decimal valorVenda)
{
var produto = new Produto { ValorCusto = valorCusto, ValorVenda = valorVenda };
validator.ShouldHaveValidationErrorFor(p => p.ValorCusto, produto);
}
[Theory]
[InlineData(1.00, 2.00)]
[InlineData(1.50, 2.50)]
[InlineData(100.00, 200.00)]
public void ValorVenda_Valido(decimal valorCusto, decimal valorVenda)
{
var produto = new Produto { ValorCusto = valorCusto, ValorVenda = valorVenda };
validator.ShouldNotHaveValidationErrorFor(p => p.ValorVenda, produto);
}
[Theory]
[InlineData(2.00, 1.00)]
[InlineData(2.50, 1.50)]
[InlineData(200.00, 100.00)]
public void ValorVenda_Invalido(decimal valorCusto, decimal valorVenda)
{
var produto = new Produto { ValorCusto = valorCusto, ValorVenda = valorVenda };
validator.ShouldHaveValidationErrorFor(p => p.ValorVenda, produto);
}
}
Vamos ver se roda ?
No meu próximo Post vou colocar o código em teste e ver o que acontece copiando na forma original como o ChatGpt criou ! Aguardem….
Então aí está, quanto tempo você gastaria para fazer tudo isso na mão ? como eu sempre digo para meus alunos:
“Se você fosse um pedreiro e tivesse que fazer massa, iria preferir utilizar uma pá e enxada ou iria utilizar uma betoneira ?”
Então aí está, um belo exemplo de tarefa corriqueiras que podemos automatizar e utilizar mais nosso tempo para pensarmos em arquitetura, em regras de negócio, em entender as demandas do cliente melhor.
Portanto, não tenham medo (por enquanto) vamos utilizá-la da melhor forma e aprender com esta experiência !
Gostou do artigo? clique no ícone👏e me siga para ver as próximas publicações !!