Quando começamos a estudar sobre TDD (Test Driven Development) é comum surgirem algumas dúvidas, por exemplo, o que testar? como escrever testes antes do código de produção?
Este é um artigo bem prático que tem como objetivo acabar com algumas dessas dúvidas se tratando de aplicações React.
Test Driven Development
O Test Driven Development ou TDD significa Desenvolvimento Orientado a Testes e é uma prática que consiste em um ciclo curto de três passos, conhecidos como Red/Green/Refactor.
- Red: Primeiro escrevemos um teste que falha, para alguma funcionalidade que ainda será desenvolvida.
- Green: Com o teste criado, escrevemos uma solução simples para fazê-lo passar.
- Refactor: Por último refatoramos, ou seja, melhoramos o código.
Esse ciclo deve se repetir várias vezes durante todo o desenvolvimento.
Tendo isso em mente podemos ver como esse ciclo funciona na prática.
Escrevendo um teste que falha
Para acompanhar o desenvolvimento você pode baixar o repositório e fazer o checkout na branch exercise-01-start
.
Após baixar o código, crie a pasta src/components
e adicione o arquivo Highlight.test.js
com o seguinte conteúdo:
import ReactDOM from "react-dom";
import Highlight from "./Highlight";
test("renders a value", () => {
const container = document.createElement("div");
document.body.appendChild(container);
ReactDOM.render(<Highlight />, container);
expect(document.body.textContent).toBe("3000");
});
A função test
recebe uma descrição do teste como primeiro parâmetro. É uma boa prática sempre começar com um verbo no presente. O segundo parâmetro é uma função anônima com o código do teste.
Uma const
chamada container
tem como valor uma div
, que é o elemento onde o componente será renderizado.
O método render
do ReactDOM
é utilizado para renderizar o componente.
Por último, é feita uma chamada a função expect
, ela fornece uma lista de métodos que nos permitem fazer diferentes asserções. Neste caso, verificamos se o textContent
da página é 3000
.
Execute o comando npm test
, veja que o teste está falhando, isso já era esperado, porque ainda estamos no primeiro passo do ciclo.
Fazendo o teste passar
Agora crie o arquivo Highlight.js
dentro de src/components
, com o seguinte conteúdo:
const Highlight = () => <div>3000</div>;
export default Highlight;
Por enquanto não precisamos de nada além disso para que o teste passe.
Refatorando o código
Adicionamos um valor “na mão”, apenas para o teste passar, mas vamos precisar que o componente funcione com outros valores, para isso vamos fazer a seguinte alteração no teste:
ReactDOM.render(<Highlight value="3000" />, container);
E logo em seguida no componente:
const Highlight = ({ value }) => <div>{value}</div>;
Fizemos essas mudanças na intenção ter um código melhor, que funcione com diferentes valores, mas quem garante que funciona?
Repetindo o ciclo
Para garantir que o componente está funcionando como esperado, podemos repetir o ciclo escrevendo outro teste. Adicione o seguinte código no arquivo Highlight.test.js
:
test("renders another value", () => {
const container = document.createElement("div");
document.body.appendChild(container);
ReactDOM.render(<Highlight value="5000" />, container);
expect(document.body.textContent).toBe("5000");
});
Execute os testes novamente. Note que o segundo teste falha e com um erro bem estranho:
Expected substring: "5000"
Received string: "30005000"
Isso acontece porque adicionamos um elemento ao body
e não o removemos após a execução do primeiro teste.
Removendo efeitos colaterais
Para que o teste passe, devemos garantir que o que foi feito em um não interfira no resultado do outro. Podemos remover todos os elementos do body
após cada teste. A função afterEach
do Jest permite fazer isso de uma forma bem simples. Adicione o seguinte código antes dos testes:
afterEach(() => {
document.body.innerHTML = "";
});
Removendo código duplicado
Se olharmos bem o arquivo de teste, podemos ver claramente que alguns itens se repetem. Essa é a hora em que devemos resistir a tentação de passar para o próximo componente e trabalhar duro para deixar nosso código o mais limpo possível.
Crie a seguinte função no arquivo de testes:
function render(component) {
const container = document.createElement("div");
document.body.appendChild(container);
ReactDOM.render(component, container);
}
Ela contém o código que se repete nos dois testes. Com essa função, podemos refatorar os testes, tornando-os mais simples:
test("renders a value", () => {
const value = "3000"; // Arrange
render(<Highlight value={value} />); // Act
expect(document.body.textContent).toBe(value); // Assert
});
test("renders another value", () => {
const value = "5000"; // Arrange
render(<Highlight value={value} />); // Act
expect(document.body.textContent).toBe(value); // Assert
});
Para saber se um teste é bom, você deve ser capaz de identificar cada uma das seguintes etapas:
- Arrange: Faz o setup das dependências de teste
- Act: Executa o código de produção em teste
- Assert: Verifica se as expectativas são atendidas
Mas isso não é tudo, podemos deixar os testes ainda melhores, garantindo que eles atendam alguns requisitos:
- Sejam descritivos
- Independentes de outros testes
- Não tenham efeitos colaterais
O ideal é sempre buscar atender todos esses requisitos, você vai ganhar muito com isso e provavelmente evitar algumas dores de cabeça no futuro.
Conclusão
Nesse artigo desenvolvemos um componente React seguindo o TDD, fiz o possível para que não ficasse muito longo.
Se esse conteúdo te ajudou ou se ficou alguma dúvida, deixa um comentário, isso me ajuda a saber se devo criar mais conteúdo desse tipo.
Ah! O código completo pode ser encontrado nesse repositório. Abraço!