Escrevendo validação e testes unitários em .NET usando o ChatGPT

Marcio Nizzola
5 min readFeb 14, 2023

--

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 ?

frase criada pelo ChatGpt falando sobre o medo dos desenvolvedores sob a ótica do Mestre Yoda

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 !!

--

--

Marcio Nizzola
Marcio Nizzola

Written by Marcio Nizzola

Microsoft MVP | Software Architect na CI&T | Prof. da Etec Itu | Membro Fundador da Comunidade Itu Developers.

No responses yet