Desenvolvimento

5 fev, 2019

Trabalhando com TDD em projetos .NET

Publicidade

O Test-Driven Development é uma prática onde desenvolve-se um projeto ou parte dele pensando, primeiramente, em testes. O próprio nome traduzido já é uma auto-explicação, Desenvolvimento Dirigido por Testes. Tal prática se tornou popular e, consequentemente, muito utilizada devido a garantia de funcionamento e qualidade de itens de desenvolvimento entregues.

Neste contexto, surge algumas perguntas, tais como:

Qual a vantagem em desenvolver assim?

  • Maior cobertura de testes no código
  • Garantia que os requisitos solicitados funcionem
  • Qualidade do código (onde o próprio código de testes traz informações sobre a qualidade do código produzido)
  • Garantia da entrega de um produto com maior qualidade

Qual a diferença entre utilizar TDD e criar os testes após o desenvolvimento?

A qualidade final de um código é baseada nos testes criados. A diferença entre a maneira que se cria os testes está no retorno de feedback do teste para o desenvolvedor.

Se um programador começa a criar os testes primeiro, ele recebe feedback constantemente, pois o mesmo consegue dividir seu trabalho em pequenas tarefas. Onde o mesmo consegue ter os seguintes passos:

  • Escrever um teste
  • Implementar um pedaço da funcionalidade
  • Executar o teste

A cada teste escrito, ele recebe um feedback. E, com isso, fica fácil de alterar o código feito.

Quando o programador desenvolve primeiro e depois, ao final, cria os testes, ele não recebeu nenhum feedback. E ao criar os testes, caso tenha que realizar alguma alteração, a mesma pode ser complexa e trabalhosa e levar um tempo maior para ser feita, custando caro.

Isso irá diminuir minha produtividade?

Onde pratica-se o TDD, obviamente o desenvolvedor irá gastar um maior tempo criando testes, mas não significa ser menos ou mais produtivo.

Tal tempo gasto, é gasto de maneira inteligente. Pois os testes criados, irão perdurar até o fim do projeto/código, ou seja, irá durar por muito tempo. E, além isso, podem ser executados a qualquer momento e quantas vezes for necessário, visando a garantia do código feito.

Também, ao criar/pensar em testes primeiro, facilita as modificações no código que for preciso, como citado acima.

Como funciona o TDD?

TDD é uma técnica de desenvolvimento baseado em um ciclo, independente da linguagem de programação, composto por passos que são:

  1. Criar um cenário de teste baseado em uma regra de negócio
  2. Criar o teste baseado no cenário
  3. Executar o teste criado (irá falhar)
  4. Escrever o código até que o teste apresente sucesso
  5. Refatorar o código desenvolvido
  6. Executar o teste novamente

Basicamente, é o que está apresentado na imagem abaixo:

Hands-on

Regra de negócio

Antes de tudo, é preciso ler e entender qual é a regra de negócio que será solicitada. Sendo assim, tem-se: Dado itens de produtos, é necessário permitir o cadastro de tais itens. Onde cada produto terá as seguintes informações com seus respectivos tipos:

  • Nome [string]
  • Código do produto [string]
  • Descrição [string]
  • Valor de custo [decimal]
  • Valor de venda [decimal]

Deve-se considerar as seguintes regras, ao realizar o cadastro de algum item:

  • Os campos obrigatórios serão: ‘Nome’, ‘Código do produto’ e ‘Valor de custo’
  • O campo ‘Valor de custo’ deve ser maior do que zero
  • A quantidade de caracteres do campo ‘Nome’ deve ser inferior a 100
  • A quantidade de caracteres do campo ‘Descrição’ deve ser inferior a 500
  • O campo ‘Código do produto’ deverá conter, exatamente, 6 caracteres
  • O ‘Valor de venda’ será calculado automaticamente, onde constituirá do ‘Valor de custo’ + 15% de seu valor

Cenário de teste

Dado a regra de negócio acima, necessita-se criar os cenários de teste. No caso, cria-se apenas um como demonstrativo, sendo ele:

Deve-se testar um produto válido, onde se apresenta um item composto pelos seguintes dados:

  • Nome: Notebook Acer
  • Código: 849071
  • Valor de custo: R$ 1.843,25

Deve-se validar todos os campos, de acordo com as regras, onde o resultado deverá ser sucesso.

Construção do teste

Com o cenário de teste já definido, pode-se criar os testes via código, como é exibido abaixo:

[TestClass]
public class ProdutoTeste
{
	[TestMethod]
	[DataRow("Notebook Acer", "849071", 1843.25)]
	public void SalvarProduto_ComDadosValidos_Sucesso(string nome, string codigo, double valorCusto)
	{
		//action:
		Produto produto = new Produto(nome, codigo, valorCusto);

		//asserts:
		Assert.IsNotNull(produto);
		Assert.IsTrue(!string.IsNullOrWhiteSpace(produto.Nome));
		Assert.IsTrue(!string.IsNullOrWhiteSpace(produto.Codigo));
		Assert.IsTrue(produto.ValorCusto > 0);
		Assert.IsTrue(produto.Nome.Length <= 100);
		Assert.IsTrue(!string.IsNullOrEmpty(produto.Descricao) ? produto.Descricao.Length <= 500 : true);
		Assert.AreEqual(produto.Codigo.Length, 6);
		Assert.AreEqual(produto.ValorVenda, 2119.74);
	}
}

Analisando o código, nota-se o seguinte:

  • Para que um produto exista, é necessário informar o nome, código e valor de custo do mesmo. Com isso, tais campos são cobrados no construtor da classe e a mesma não deve permitir ser instanciada sem tais campos, atendendo a primeira regra de validação.
  • É testado se o campo referente ao Valor de Custo é maior do que zero, atendendo a segunda regra de validação
  • É testado se o campo referente ao nome tem o número de caracteres menor ou igual a 100, atendendo a terceira regra de validação
  • É testado se o campo referente a descrição tem o número de caracteres menor ou igual a 500, caso o mesmo exista, atendendo a quarta regra
  • É testado se o campo referente ao código do produto tem o número de caracteres igual, exatamente, a 6, atendendo a quinta regra
  • É testado se o campo referente ao valor da venda é igual a 2119.7375, valor obtido pela fórmula descrita na regra de negócio, atendendo a sexta regra

Execução do teste

Após o teste já estar desenvolvido, pode-se executá-lo. Como ainda não tem-se nenhum código criado, o teste não será executado e irá dar erro de compilação.

Escrita do código

Após analisar o teste criado, deve-se desenvolver o código que irá atendê-lo, ou seja, criar a classe Produto com todos os atributos esperados.

public class Produto
{
	public Produto(string nome, string codigo, double valorCusto)
	{
		Nome = nome;
		Codigo = codigo;
		ValorCusto = valorCusto;
	}

	public string Nome { get; set; }

	public string Codigo { get; set; }

	public string Descricao { get; set; }

	public double ValorCusto { get; set; }

	public double ValorVenda => Math.Round((ValorCusto * 1.15), 2);
}

Refatoração do código escrito

Como o código desenvolvido está atendendo perfeitamente as regras de negócio, não será necessário refatorá-lo. Apenas se houver alguma mudança na própria regra.

Execução novamente do teste

Por fim, ao executar o teste novamente, nota-se que o mesmo irá ter um resultado de sucesso.

Resultado de sucesso do teste executado

Conclusão

Seguindo tais práticas, garante-se que o código desenvolvido sempre estará coberto por uma certa quantidade de testes. Onde, a cada alteração do código, pode-se assegurar que o mesmo estará em funcionamento.

É válido, também, considerar que os teste não são imutáveis. Pois as regras de negócio podem sofrer alterações.