Bem-vindo de volta! No último artigo, conversamos sobre a importância dos testes e como eles podem ser um diferencial na nossa jornada como desenvolvedores. Hoje, daremos um passo além e mergulharemos em um aspecto mais prático e aplicado dos testes unitários, focando na ferramenta Jest. Se você ainda não leu o artigo anterior eu sugiro a leitura.
#TesteSemNeura - Testes unitários, como comecei e como posso te ajudar.
Iury Nogueira ・ Aug 25 '22
O Jest é uma das ferramentas mais populares para testes em JavaScript, não apenas simplifica o processo, mas também torna a experiência de escrever testes agradável, você pode usa-lo para testar seus códigos frontend e backend. Está preparado para elevar suas habilidades de teste e deixar o medo de lado? Então, vamos lá!
Antes de começarmos você precisa configurar o jest no seu projeto, para isso é só chamar nosso velho amigo npm, execute o comando na raiz do seu projeto.
npm install --save-dev jest
ou execute com o Yarn:
yarn add --dev jest
Particularmente eu gosto sempre de adicionar um novo script ao meu package.json para executar os testes, dessa forma:
"scripts": {
"test": "jest"
}
Agora é só executar npm run test ou yarn test.
Vamos pegar um caso bem didático para nosso primeiro teste, quero que você se atente principalmente a estrutura do teste, eu costumo escrever testes pensando sempre na seguinte ordem: O que meu teste tem que validar, preparação/processamento e o que eu espero que seja correto na saída do processamento. Vou deixar mais claro com o exemplo abaixo:
// primeiro.test.js
test('dois mais dois é igual a quatro', () => {
expect(2 + 2).toBe(4);
});
para executar esse teste execute:
npm test
ou execute com o Yarn:
yarn test
você verá essa saída no terminal indicando que seu teste passou.
note que eu procuro validar que "dois mais dois é igual a quatro", e eu espero (expect) que o resultado do processamento dessa soma seja 4 (toBe(4)). Por enquanto vamos nos atentar nisso, na estrutura de teste, o que se deve testar e o que esperar de cada teste, esse conceito é muito importante.
Vamos supor que você tenha uma função que deve recebe um valor em real (nossa moeda) e converte esse valor para dólar considerando que o dólar custa 5 reais. Vamos lá!
// conversorRealParaDolar.test.js
// Função que converte um valor de reais para dólar
function converterRealParaDolar(valor) {
const valorDolar = 0.2;
const valorConvertido = valor * valorDolar;
return Number(valorConvertido.toFixed(2));
}
test('100 reais deve ser 20 dólares', () => {
expect(converterRealParaDolar(100)).toBe(20);
});
test('deve lançar um erro para valores negativos', () => {
expect(() => converterRealParaDolar(-100)).toThrow(
'O valor a ser convertido deve ser um número positivo.'
);
});
Note que eu chamo nossa função que converte e retorna o valor em dólar, mais uma vez checo o resultado com o toBe(), também adicionei um caso que um bom QA testaria, um número negativo! Nesses casos utilizamos o toThrow para checar uma exception, sempre é importante cobrir todos os casos possíveis de entrada para sua função e mapear os casos no teste, você pode escrever mais de um caso de test para uma mesma funcionalidade. Agora execute os testes com o comando que já falei anteriormente, você verá o seguinte resultado:
O segundo caso de teste quebrou pois nossa função não lança um erro quando um número é negativo, "mas Iury, é claro que o teste vai quebrar, como tu tá testando uma coisa que não foi implementada?" Isso é o que a gente chama de TDD! Basicamente você implementa todos os casos de teste e o desafio é você ir tirando o "vermelho" dos seus testes quando for implementando a função, mas isso é assunto para outro artigo, vamos seguir somente com esse breve conceito, um "ifzinho" no nosso código resolverá esse problema.
// funcao atualizada
function converterRealParaDolar(valor) {
const valorDolar = 0.2;
// chique né?
if (isNaN(valor) || valor <= 0) {
throw new Error('O valor a ser convertido deve ser um número positivo.');
}
const valorConvertido = valor * valorDolar;
return Number(valorConvertido.toFixed(2));
}
execute os testes novamente e veja que nosso teste passou, não é satisfatório? :)
O expect possui vários matchers, o mais comum como já usamos aqui é o toBe, outro muito comum de se usar no dia a dia é o toHaveLength onde você pode checar o tamanho de um array ou de uma string como no exemplo abaixo (repare também no not :D):
expect([1, 2, 3]).toHaveLength(3);
expect('abc').toHaveLength(3);
expect('').not.toHaveLength(5);
para conferir todos os matchers sugiro que você consulte a doc
Outro aspecto fundamental nos testes unitários é a cobertura de código, no exemplo da função de conveterRealParaDoar ela está 100% coberta porque nossos testes passam por todas as linhas de código, caso o teste da exception fosse removido nós não teríamos todo nossa função validada, por isso é importante sempre manter essa cobertura alta para que tenhamos o número máximo de casos possíveis mapeados em nossos testes, isso vai te ajudar a não ter aquele medo que falamos no primeiro artigo e você vai se sentir mais a vontade para realizar mudanças no código, agora vamos configurar a coleta do coverage!
Abra o arquivo de configuração do Jest (normalmente jest.config.js ou no bloco jest em seu package.json).
Adicione essa configuração para habilitar a geração de cobertura:
// jest.config.js
module.exports = {
collectCoverage: true,
collectCoverageFrom: ['src/**/*.js'], // esse é o caminho dos seus testes,
coverageReporters: ['json', 'lcov', 'text', 'html'], // eu gosto de adicionar o HTML porque ele cria uma página bonitinha com vários progress.
};
- Só executar!
npm test --coverage
ou execute com o Yarn:
yarn test --coverage
Acredito que com isso nós temos nossa porta de entrada para os testes, aconselho praticar com suas funções diariamente, no próximo artigo eu vou abordar sobre TDD!
Agradeço por sua leitura até aqui e gostaria muito do seu feedback, estou comprometido para melhorar e fornecer um conteúdo útil para ajudar no desenvolvimento de vários outros devs por ai a fora. Obrigado!
Top comments (2)
Eai meu senhor, como vai?
Alguns feedbacks após ler seu artigo e tentar seguir. Arquitetura de pastas, onde seria um bom lugar, arquiteturalmente falando para manter os arquivos de testes, talvez seja uma dúvida frequente pra quem tá começando no mundo de testes. Outra coisa, é que eu segui o que você falou e nenhum teste foi encontrado
e só depois eu descobri que o jest identifa os testes pelo
.teste
no nome do arquivoNo mais, parabéns pela iniciativa!
Olá @ami_aram
Sobre a arquitetura de pastas, não há um padrão ou convenção que diga a forma mais correta de organizar esses arquivos. Porém, há muitas conversas na comunidade e práticas.
Por exemplo:
há devs que criam o arquivo de teste no mesmo lugar do arquivo que será testado, tendo o mesmo nome com o diferencial da extensão que fica .test ou .spec.
Já há outros devs que preferem concentrar esses arquivos de teste dentro de uma pasta geral chamada "tests" podendo ou não estar dentro da pasta principal do projeto "src", e dentro dessas pastas você organizar sub-pastas para concentrar testes unitários, integração e ponta-a-ponta(e2e).
Eu particularmente prefiro a segunda opção, pois visualmente agrada meus olhos ao ver as coisas menos embaraçadas.
Mas fica a sei critério como organizar, desde que lá no package.json quando você configurar os scripts de comandos para executar os testes, você especificar o caminhos dos teste certinho.
Abraço amigo!