Usando o chat do Bing como um aliado para escrever testes de software
Tags: csharp, chatgpt, tests, dotnet
Published: 2023-05-04 16:17:26

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8wc95sb0bdzfe8j5v6v9.png)
> Imagem gerada com a ferramenta [Criador de Imagens do Bing](https://www.bing.com/images/create/).


A criação de testes é uma parte crucial do processo de desenvolvimento de software. Pois garante que o software funcione corretamente e atenda às expectativas dos usuários.

No entanto, um desafio enfrentado pelos desenvolvedores é obter dados falsos e aleatórios para serem usados nestes testes. Dados falsos são necessários para simular cenários realistas e garantir que o software seja capaz de lidar com diferentes situações.

Para auxiliar na geração de dados falsos para os testes, existe uma excelente biblioteca chamada **Bogus**, disponível [nesse repositório do Nuget](https://www.nuget.org/packages/Bogus/).

Esta biblioteca auxilia na geração de instâncias de dados fakes, de acordo com as classes do seu projeto.

Um pequeno exemplo:

```csharp
 public class NotaFiscal
 
    public long Id { get; set; }
    public int Operacao { get; set; }
    public string TipoEmissao { get; set; }
    public string ModeloDocumento { get; set; }
    public string Situacao { get; set; }
    public int Serie { get; set; }
    public int Numero { get; set; }
    public DateTime DataEmissao { get; set; }
    public DateTime DataEntradaSaida { get; set; } 
}
```
Para gerar uma instância fake da classe NotaFiscal, poderíamos fazer o seguinte código usando o Bogus:

```csharp
using Bogus;

namespace Exemplo
{
    public class NotaFiscalFaker : Faker<NotaFiscal>
    {
        public NotaFiscalFaker()
        {
            RuleFor(n => n.Id, f => f.Random.Long(1));
            RuleFor(n => n.Operacao, f => f.Random.Int(1));
            RuleFor(n => n.TipoEmissao, f => f.Random.String2(10));
            RuleFor(n => n.ModeloDocumento, f => f.Random.String2(10));
            RuleFor(n => n.Situacao, f => f.Random.String2(10));
            RuleFor(n => n.Serie, f => f.Random.Int(1));
            RuleFor(n => n.Numero, f => f.Random.Int(1));
            RuleFor(n => n.DataEmissao, f=>f.Date.Recent());
            RuleFor(n=>n.DataEntradaSaida,f=>f.Date.Recent());
        }
    }
}
```

Você pode usar esse builder da seguinte maneira:

```csharp
var faker = new NotaFiscalFaker();
var fakeNotaFiscal = faker.Generate();
```

Com este pequeno exemplo, dá pra perceber que o Bogus, é uma mão-na-roda. Mas imagine um cenário em que tenhamos centenas de classes de dados extensas, daria um trabalhão, gerar um builder para cada uma dessas classes. Manter esses builders, à medida que estas classes vão sendo evoluídas, também dará um trabalho extra.

O [Chat do novo Bing](https://www.bing.com/search?q=Bing+AI&showconv=1&FORM=hpcodx), pode nos ajudar com este trabalho braçal e maçante.

Abaixo, descrevo minha conversa com o Chat do Bing, e mostro o excelente resultado que ele me deu, durante a geração de builders, para as seguintes classes em c#:

**NotaFiscal**:

```csharp
public class NotaFiscal
{
    public long Id { get; set; }

    /// <summary> 
    /// IND_OPER - Indicador do tipo de operação:
    /// 
    /// <para>0 - Entrada</para> 
    /// <para>1 - Saída</para> 
    /// </summary> 
    public int Operacao { get; set; }

    /// <summary> 
    /// IND_EMIT - Indicador do emitente do documento fiscal:
    /// 
    /// <para>0 - Emissão própria</para> 
    /// <para>1 - Terceiros</para> 
    /// </summary> 
    public string TipoEmissao { get; set; }

    public NotaFiscalProdutoNaturezaOperacao NaturezaOperacao { get; set; }

    public Participante Participante { get; set; }

    public string ModeloDocumento { get; set; }

    public string Situacao { get; set; }

    public int Serie { get; set; }

    public int Numero { get; set; }

    public string Chave { get; set; }

    public DateTime DataEmissao { get; set; }

    public DateTime DataEntradaSaida { get; set; }

    public decimal ValorTotal { get; set; }

    public int TipoPagamento { get; set; }

    public decimal ValorDesconto { get; set; }

    public decimal ValorAbatimento { get; set; }

    public decimal ValorMercadorias { get; set; }

    public int TipoTransporte { get; set; }

    public decimal ValorFrete { get; set; }

    public decimal ValorSeguro { get; set; }

    public decimal ValorDespesas { get; set; }

    public decimal ICMS_BC { get; set; }

    public decimal ICMS_Aliquota { get; set; }

    public decimal ICMS_Valor { get; set; }

    public decimal ICMS_ST_BC_Valor { get; set; }

    public decimal ICMS_ST_Retido_Valor { get; set; }

    public decimal IPI_Valor { get; set; }

    public decimal PIS_Valor { get; set; }

    public decimal PIS_ST_Valor { get; set; }

    public decimal COFINS_Valor { get; set; }

    public decimal COFINS_ST_Valor { get; set; }

    public List<NotaFiscalProduto> Produtos { get; set; }

}
```

**Participante:**

```csharp
public class Participante
{
    public long Id { get; set; }
    public string Codigo { get; set; }
    public string Nome { get; set; }
    public string Cod_Pais { get; set; }
    public string CNPJ { get; set; }
    public string CPF { get; set; }
    public string IE { get; set; }
    public string SUFRAMA { get; set; }
    public string EnderecoCod_Mun { get; set; }
    public string EnderecoLogradouro { get; set; }
    public string EnderecoNumero { get; set; }
    public string EnderecoComplemento { get; set; }
    public string EnderecoBairro { get; set; }
}
```

**Produto:**

```csharp
public class Produto
{
    public long Id { get; set; }
    public string Codigo { get; set; }
    public string Descricao { get; set; }
    public NotaFiscalProdutoUnidade Unidade { get; set; }
    public int Origem { get; set; }
    public string NCM { get; set; }
    public string CEST { get; set; }
    public decimal ICMS_Aliquota { get; set; }
}
```

**NotaFiscalProduto:**

```csharp
public class NotaFiscalProduto
{
    public long NotaFiscalId { get; set; }
    public int Numero { get; set; }
    public Produto Produto { get; set; }
    public decimal Quantidade { get; set; }
    public decimal ValorTotal { get; set; }
    public decimal Desconto { get; set; }
    public int Movimentado { get; set; }
    public string ICMS_CST { get; set; }
    public string CFOP { get; set; }
    public decimal ICMS_BC { get; set; }
    public decimal ICMS_Aliquota { get; set; }
    public decimal ICMS_Valor { get; set; }
    public decimal ICMS_ST_BC { get; set; }
    public decimal ICMS_ST_Aliquota { get; set; }
    public decimal ICMS_ST_Valor { get; set; }
    public int IPI_Apuracao { get; set; }
    public string IPI_CST { get; set; }
    public string IPI_Enquadramento { get; set; }
    public decimal IPI_BC { get; set; }
    public decimal IPI_Aliquota { get; set; }
    public decimal IPI_Valor { get; set; }
    public string PIS_CST { get; set; }
    public decimal PIS_BC { get; set; }
    public decimal PIS_Aliquota { get; set; }
    public decimal PIS_BC_Quantidade { get; set; }
    public decimal PIS_Aliquota_Reais { get; set; }
    public decimal PIS_Valor { get; set; }
    public string COFINS_CST { get; set; }
    public decimal COFINS_BC { get; set; }
    public decimal COFINS_Aliquota { get; set; }
    public decimal COFINS_BC_Quantidade { get; set; }
    public decimal COFINS_Aliquota_Reais { get; set; }
    public decimal COFINS_Valor { get; set; }
    public string ContaContabil { get; set; }
    public decimal ValorAbatimento { get; set; }
}
```

**NotaFiscalProdutoUnidade:**

```csharp
public class NotaFiscalProdutoUnidade
{
    public long Id { get; set; }
    public string Codigo { get; set; }
    public string Simbolo { get; set; }
}
```

**NotaFiscalProdutoNaturezaOperacao:**

```csharp
public class NotaFiscalProdutoNaturezaOperacao
{
    public long Id { get; set; }
    public string Codigo { get; set; }
    public string Descricao { get; set; }
}
```

Abaixo, a transcrição da minha conversa com o chat do Bing:


**Meu prompt**: 

_1 - Usando a biblioteca Bogus para .Net, gere um builder para criar instâncias fakes da classe "NotaFiscalProdutoNaturezaOperacao"._

**Resposta do Chat:**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/losskekta11wo9j9ocx3.png)

Então segui, com os seguintes prompts:

_2 - Usando a biblioteca Bogus para .Net, gere um builder para criar instâncias fakes da classe "NotaFiscalProdutoUnidade"._

_3 - Usando a biblioteca Bogus para .Net, gere um builder para criar instâncias fakes da classe "NotaFiscalProduto"._

_4 - Usando a biblioteca Bogus para .Net, gere um builder para criar instâncias fakes da classe "Produto"._

_5 - Usando a biblioteca Bogus para .Net, gere um builder para criar instâncias fakes da classe "Participante"._

Neste momento, algo interessante ocorreu: Eu esqueci de informar para o chat do Bing, a definição da classe **Participante**:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9ijv12c4rzqbnuxiz0s7.png)

_6 - Usando a biblioteca Bogus para .Net, gere um builder para criar instâncias fakes da classe "NotaFiscal"._



Em alguns minutos, consegui criar os builders para todo o modelo de dados da API:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s1v9w9st0heeehgw3xcc.png)

Obtendo como resultado as seguintes classes:

NotaFiscalProdutoNaturezaOperacaoFaker
```csharp
public class NotaFiscalProdutoNaturezaOperacaoFaker : Faker<NotaFiscalProdutoNaturezaOperacao>
{
    public NotaFiscalProdutoNaturezaOperacaoFaker()
    {
        RuleFor(n => n.Id, f => f.Random.Long(1));
        RuleFor(n => n.Codigo, f => f.Random.String2(10));
        RuleFor(n => n.Descricao, f => f.Lorem.Sentence());
    }
}
```

NotaFiscalProdutoUnidadeFaker
```csharp
public class NotaFiscalProdutoUnidadeFaker : Faker<NotaFiscalProdutoUnidade>
{
    public NotaFiscalProdutoUnidadeFaker()
    {
        RuleFor(n => n.Id, f => f.Random.Long(1));
        RuleFor(n => n.Codigo, f => f.Random.String2(10));
        RuleFor(n => n.Simbolo, f => f.Random.String2(3));
    }
}
```

NotaFiscalProdutoFaker
```csharp
public NotaFiscalProdutoFaker()
{
    RuleFor(n => n.NotaFiscalId, f => f.Random.Long(1));
    RuleFor(n => n.Numero, f => f.Random.Int(1));
    RuleFor(n => n.Produto, f => new ProdutoFaker().Generate());
    RuleFor(n => n.Quantidade, f => f.Random.Decimal(1));
    RuleFor(n => n.ValorTotal, f => f.Random.Decimal(1));
    RuleFor(n => n.Desconto, f => f.Random.Decimal(1));
    RuleFor(n => n.Movimentado, f => f.Random.Int(1));
    RuleFor(n => n.ICMS_CST, f => f.Random.String2(10));
    RuleFor(n => n.CFOP, f => f.Random.String2(10));
    RuleFor(n => n.ICMS_BC, f => f.Random.Decimal(1));
    RuleFor(n => n.ICMS_Aliquota, f => f.Random.Decimal(1));
    RuleFor(n => n.ICMS_Valor, f => f.Random.Decimal(1));
    RuleFor(n => n.ICMS_ST_BC, f => f.Random.Decimal(1));
    RuleFor(n => n.ICMS_ST_Aliquota, f => f.Random.Decimal(1));
    RuleFor(n => n.ICMS_ST_Valor, f => f.Random.Decimal(1));
    RuleFor(n => n.IPI_Apuracao, f => f.Random.Int(1));
    RuleFor(n => n.IPI_CST, f => f.Random.String2(10));
    RuleFor(n => n.IPI_Enquadramento, f => f.Random.String2(10));
    RuleFor(n => n.IPI_BC, f => f.Random.Decimal(1));
    RuleFor(n => n.IPI_Aliquota, f => f.Random.Decimal(1));
    RuleFor(n => n.IPI_Valor, f => f.Random.Decimal(1));
    RuleFor(n => n.PIS_CST, f => f.Random.String2(10));
    RuleFor(n => n.PIS_BC, f => f.Random.Decimal(1));
    RuleFor(n => n.PIS_Aliquota, f => f.Random.Decimal(1));
    RuleFor(n => n.PIS_BC_Quantidade, f => f.Random.Decimal(1));
    RuleFor(n => n.PIS_Aliquota_Reais, f => f.Random.Decimal(1));
    RuleFor(n => n.PIS_Valor, f => f.Random.Decimal(1));
    RuleFor(n => n.COFINS_CST, f => f.Random.String2(10));
    RuleFor(n => n.COFINS_BC, f => f.Random.Decimal(1));
    RuleFor(n => n.COFINS_Aliquota, f => f.Random.Decimal(1));
    RuleFor(n => n.COFINS_BC_Quantidade, f => f.Random.Decimal(1));
    RuleFor(n => n.COFINS_Aliquota_Reais, f => f.Random.Decimal(1));
    RuleFor(n => n.COFINS_Valor, f => f.Random.Decimal(1));
}
```

ProdutoFaker
```csharp
public class ProdutoFaker : Faker<Produto>
{
    public ProdutoFaker()
    {
        RuleFor(n => n.Id, f => f.Random.Long(1));
        RuleFor(n => n.Codigo, f => f.Random.String2(10));
        RuleFor(n => n.Descricao, f => f.Lorem.Sentence());
        RuleFor(n => n.Unidade, f => new NotaFiscalProdutoUnidadeFaker().Generate());
        RuleFor(n => n.Origem, f => f.Random.Int(1));
        RuleFor(n => n.NCM, f => f.Random.String2(10));
        RuleFor(n => n.CEST, f => f.Random.String2(10));
        RuleFor(n => n.ICMS_Aliquota, f => f.Random.Decimal(1));
    }
}
```

ParticipanteFaker
```csharp
public class ParticipanteFaker : Faker<Participante>
{
    public ParticipanteFaker()
    {
        RuleFor(n => n.Id, f => f.Random.Long(1));
        RuleFor(n => n.Codigo, f => f.Random.String2(10));
        RuleFor(n => n.Nome, f => f.Name.FullName());
        RuleFor(n => n.Cod_Pais, f => f.Address.CountryCode());
        RuleFor(n => n.CNPJ, f => f.Company.Cnpj());
        RuleFor(n => n.CPF, f => f.Person.Cpf());
        RuleFor(n => n.IE, f => f.Random.String2(10));
        RuleFor(n => n.SUFRAMA, f => f.Random.String2(10));
        RuleFor(n => n.EnderecoCod_Mun, f => f.Random.String2(10));
        RuleFor(n => n.EnderecoLogradouro, f => f.Address.StreetName());
        RuleFor(n => n.EnderecoNumero, f => f.Address.BuildingNumber());
        RuleFor(n => n.EnderecoComplemento, f => f.Address.SecondaryAddress());
        RuleFor(n => n.EnderecoBairro, f => f.Address.County());
    }
}
```

NotaFiscalFaker
```csharp
public class NotaFiscalFaker : Faker<NotaFiscal>
{
    public NotaFiscalFaker()
    {
        RuleFor(n => n.Id, f => f.Random.Long(1));
        RuleFor(n => n.Operacao, f => f.PickRandom(new int[] { 0, 1 }));
        RuleFor(n => n.TipoEmissao, f => f.PickRandom(new string[] { "0", "1" }));
        RuleFor(n => n.NaturezaOperacao, f => new NotaFiscalProdutoNaturezaOperacaoFaker().Generate());
        RuleFor(n => n.Participante, f => new ParticipanteFaker().Generate());
        RuleFor(n => n.ModeloDocumento, f => f.Random.String2(10));
        RuleFor(n => n.Situacao, f => f.Random.String2(10));
        RuleFor(n => n.Serie, f => f.Random.Int(1));
        RuleFor(n => n.Numero, f => f.Random.Int(1));
        RuleFor(n => n.Chave, f => f.Random.String2(10));
        RuleFor(n => n.DataEmissao, f => f.Date.Recent());
        RuleFor(n => n.DataEntradaSaida, f => f.Date.Recent());
        RuleFor(n => n.ValorTotal, f => f.Random.Decimal(1));
        RuleFor(n => n.TipoPagamento, f => f.Random.Int(1));
        RuleFor(n => n.ValorDesconto, f => f.Random.Decimal(1));
        RuleFor(n => n.ValorAbatimento, f => f.Random.Decimal(1));
        RuleFor(n => n.ValorMercadorias, f => f.Random.Decimal(1));
        RuleFor(n => n.TipoTransporte, f => f.Random.Int(1));
        RuleFor(n => n.ValorFrete, f => f.Random.Decimal(1));
        RuleFor(n => n.ValorSeguro, f => f.Random.Decimal(1));
        RuleFor(n => n.ValorDespesas, f => f.Random.Decimal(1));
        RuleFor(n => n.ICMS_BC, f => f.Random.Decimal(1));
        RuleFor(n => n.ICMS_Aliquota, f => f.Random.Decimal(1));
        RuleFor(n => n.ICMS_Valor, f => f.Random.Decimal(1));
        RuleFor(n => n.ICMS_ST_BC_Valor, f => f.Random.Decimal(1));
        RuleFor(n => n.ICMS_ST_Retido_Valor, f => f.Random.Decimal(1));
        RuleFor(n => n.IPI_Valor, f => f.Random.Decimal(1));
        RuleFor(n => n.PIS_Valor, f => f.Random.Decimal(1));
        RuleFor(n => n.PIS_ST_Valor, f => f.Random.Decimal(1));
        RuleFor(n => n.COFINS_Valor, f => f.Random.Decimal(1));
        RuleFor(n => n.COFINS_ST_Valor, f => f.Random.Decimal(1));
        RuleFor(n => n.Produtos, f => new NotaFiscalProdutoFaker().Generate(f.Random.Int(5)));
    }
}
```

Repare que ele entendeu os comentários das propriedades da classe NotaFiscal:

```csharp
/// <summary> 
/// IND_OPER - Indicador do tipo de operação:
/// 
/// <para>0 - Entrada</para> 
/// <para>1 - Saída</para> 
/// </summary> 
public int Operacao { get; set; }

/// <summary> 
/// IND_EMIT - Indicador do emitente do documento fiscal:
/// 
/// <para>0 - Emissão própria</para> 
/// <para>1 - Terceiros</para> 
/// </summary> 
public string TipoEmissao { get; set; }
```

Fazendo a personalização dos valores que podem ser incluidos nestas propridades:

```csharp
RuleFor(n => n.Operacao, f => f.PickRandom(new int[] { 0, 1 }));

RuleFor(n => n.TipoEmissao, f => f.PickRandom(new string[] { "0", "1" }));
```

Com estas classes geradas, ao escrever os testes unitários, ou até os testes de integração, sempre que precisar de uma instância com dados totalmente randômicos destas classes, tudo que tenho a fazer é invocar os builders, assim:


```csharp
var faker = new NotaFiscalProdutoNaturezaOperacaoFaker();
var fakeNotaFiscalProdutoNaturezaOperacao = faker.Generate();
```

```csharp
var faker = new NotaFiscalProdutoNaturezaOperacaoFaker();
var fakeNotaFiscalProdutoNaturezaOperacao = faker.Generate();
```

```csharp
var faker = new NotaFiscalProdutoUnidadeFaker();
var fakeNotaFiscalProdutoUnidade = faker.Generate();
```

```csharp
var faker = new NotaFiscalProdutoFaker();
var fakeNotaFiscalProduto = faker.Generate();
```

```csharp
var faker = new ProdutoFaker();
var fakeProduto = faker.Generate();
```

```csharp
var faker = new ParticipanteFaker();
var fakeParticipante = faker.Generate();
```

```csharp
var faker = new NotaFiscalFaker();
var fakeNotaFiscal = faker.Generate();
```

Não é objetivo deste artigo, mostrar como criar os testes, o objetivo aqui foi somente mostrar como as inteligências artificiais, podem nos ajudar a fazer o trabalho chato e altamente suscetível à erros, de forma automática. Tudo que você precisa fazer é fornecer um contexto e caprichar nos prompts.