Desenvolvimento Dirigido por Testes (TDD) 🔁

Desenvolvimento Dirigido por Testes (TDD) 🔁

Desenvolvimento Dirigido por Testes, ou TDD, é como fazer um plano antes de começar uma viagem. Você decide para onde quer ir (o que quer que seu código faça), verifica se chegou lá (testa seu código), e se não, você descobre um caminho (escreve o código para fazer o teste passar). Depois, você olha ao redor para ver se pode melhorar algo na rota que escolheu (refatora o código).

Com TDD, você começa escrevendo um teste para a funcionalidade que quer adicionar ou o bug que precisa consertar. No início, esse teste vai falhar porque você ainda não escreveu o código que faz o que o teste espera, e isso é bom, por que significa que você tem uma meta clara.

A próxima etapa é escrever o código que satisfaz esse teste. Inicialmente, você pode até fazer algo bem simples, só para ver o teste passar. Isso pode parecer um pouco ao contrário, mas tem um bom motivo: ajuda a garantir que seu código só faz o que é realmente necessário e nada mais.

Depois que o teste passa, você tem a oportunidade de melhorar seu código, deixando-o mais limpo, organizado e eficiente. Isso é a refatoração. Como você tem os testes, pode refazer seu código com segurança, sabendo que se algo quebrar, os testes vão te avisar.

Por fim, TDD não é só sobre testar ou não esquecer de escrever testes. É uma forma de pensar sobre o design do seu software desde o início. Quando você escreve o teste primeiro, está pensando na interface e na usabilidade do seu código antes mesmo de implementá-lo. Isso pode levar a um design melhor e mais limpo.

Testes Falhando 🔴

Você começa escrevendo um teste para a funcionalidade que quer criar, e esse teste vai falhar porque a funcionalidade ainda não existe. Isso é ótimo, porque agora você tem um claro ponto de partida e sabe exatamente o que seu código precisa alcançar. Aqui você também cria um esqueleto básico da sua classe ou função, só para o teste conseguir compilar.

Testes Passando ✅

Agora é hora de fazer o teste passar, escrevendo código que atenda ao que o teste espera. No começo, o código pode ser relativamente bem simples. Não precisa ser perfeito, só precisa ver o teste ficar verde, mostrando que a funcionalidade básica está funcionando.

Refatoração ♻️

Com os testes passando, você dá uma olhada crítica no seu código e vê como pode melhorá-lo sem mudar o que ele faz. Você remove redundâncias, limpa o código, e faz ajustes que deixam o código mais claro e fácil de manter.

Exemplo: Carrinho de Compras 🛒

Imagine que você tem um objeto Book com propriedades como título, ISBN e preço, e um objeto ShoppingCart onde você pode adicionar livros, calcular o preço total e remover livros.

Estado Vermelho 🚩: Primeiro, você escreve um teste para a nova funcionalidade do seu carrinho de compras. Inicialmente, esse teste vai falhar porque ShoppingCart ainda não tem o método add ou getTotal.

// ShoppingCart.test.js
const ShoppingCart = require(‘./ShoppingCart’);
const Book = require(‘./Book’);

describe(‘ShoppingCart’, () => {
it(‘calculates total price for books in the cart’, () => {
const book1 = new Book(“book1”, 10, “1”);
const book2 = new Book(“book2”, 20, “2”);
const cart = new ShoppingCart();
cart.add(book1);
cart.add(book2);
expect(cart.getTotal()).toBe(30);
});
});

Estado Verde 🟢: Depois, você implementa o mínimo necessário para fazer o teste passar. Aqui está uma implementação inicial para a classe ShoppingCart e a classe Book.
Com isso, quando você rodar o teste novamente, ele deve passar, porque ShoppingCart agora realiza a funcionalidade básica esperada.

// Book.js
class Book {
constructor(title, price, isbn) {
this.title = title;
this.price = price;
this.isbn = isbn;
}
}

module.exports = Book;

// ShoppingCart.js
class ShoppingCart {
constructor() {
this.items = [];
this.total = 0;
}

add(book) {
this.items.push(book);
this.total += book.price;
}

getTotal() {
return this.total;
}
}

module.exports = ShoppingCart;

Estado Amarelo 🟡: Pode ser interessante garantir que as propriedades do Book sejam privadas e acessíveis apenas através de métodos getters e setters.
Aqui está como poderia ser a refatoração da classe Book:

// Book.js (refatorado)
class Book {
constructor(title, price, isbn) {
this._title = title;
this._price = price;
this._isbn = isbn;
}

get title() {
return this._title;
}

get price() {
return this._price;
}

get isbn() {
return this._isbn;
}
}

module.exports = Book;

Após a refatoração, você deve rodar os testes novamente para garantir que tudo ainda está funcionando como deveria. Isso completa um ciclo de TDD. Agora, você pode adicionar mais funcionalidades ao carrinho, como remover itens, e para cada nova funcionalidade, você começaria um novo ciclo de TDD.

A maior parte desse conteúdo veio do livro “Engenharia de Software Moderna”, escrito por Marco Tulio Valente. Esse livro é um tesouro cheio de dicas sobre como criar testes do jeito certo, usando o que tem de mais novo e eficiente no mundo da programação. Entretanto, a única diferença, é que o livro é em Java e aqui eu adaptei para utilizar Javascript.

Leave a Reply

Your email address will not be published. Required fields are marked *