Testes unitários com Jest no Node.JS
Uma parte importante do nosso trabalho como desenvolvedor é fazer testes. Durante a construção do nosso código mesmo sem perceber fazemos testes o tempo todo. O grande problema é que quando nosso código vai se tornando grande, com vários arquivos e funções, fica mais difícil testar tudo. Muitas vezes um código que estamos fazendo, pode causar um erro em uma outra parte do código que fizemos antes.
A solução é automatizar nossos testes, podemos fazer isso por meio de um framework. Hoje vou te ensinar a como usar o Jest para fazer seus testes. A configuração do Jest é fácil e vai fazer você ganhar tempo, em segundos toda sua aplicação será testada.
Instalando o Jest
Vou iniciar um projeto novo, com o código:
npm init -y
Com o arquivo "pakage.json" criado vamos a instalação do Jest como dependência.
npm install jest –save-dev
Compatibilidade com o ES6
Em resumo o ECMAScript 6 ou simplesmente ES6 foi uma atualização do Java Script CJS, lançada em 2015. Tivemos algumas mudanças com a importação / exportação de módulos.
CJS:
const modulo = require(“modulo”);
module.exports = modulo;
ES6:
import modulo from “modulo”;
export default modulo;
“test”: “node node_modules/jest/bin/jest.js”
Exemplo:
Configurando o Jest para o ES6
Para uso do Jest com ES6, temos disponível um modulo experimental que conseguimos usar sem problemas, pra ser mais exato a documentação diz que ainda podem acontecer bugs, mas como não tive problemas até hoje nos meus testes, vou ensinar as configurações necessárias.
Altere o "package.json" na raiz do seu projeto
“test”: "node --experimental-vm-modules node_modules/jest/bin/jest.js"
“type”: “module”,
Segue o exemplo:
Preparando o ambiente.
Vou criar um arquivo chamado math.js, com algumas funções que fazem operações matemáticas simples.
function soma (a, b) {
return a + b
}
function subtracao (a, b) {
return a - b
}
function multiplicacao (a, b) {
return a * b
}
function divisao (a, b) {
return a / b
}
export { soma, subtracao, multiplicacao, divisao }
Nosso objetivo é testar essas funções com o Jest, segundo as boas praticas os arquivos de testes devem ficar dentro de uma pasta chamada “test”. Vamos cria-la.
Dentro da pasta "test" vou criar o arquivo de teste, é comum usar o mesmo nome do arquivo que vamos testar seguido de ".test.js" ou ".spec.js". Meu arquivo vai ficar com o nome "math.test.js".
Lembrando que o Jest vem configurado para reconhecer arquivos que tenham em seu nome "test" ou "spec".
Fazendo o primeiro teste
Importando
A primeira coisa a fazer dentro do arquivo "math.test.js" é importar as funções que vamos testar
import { soma, subtracao, divisao, multiplicacao } from "../math"
Descrevendo o teste
Logo abaixo da importação vou descrever o meu conjunto de testes.
import { soma, subtracao, divisao, multiplicacao } from "../math"
describe('Testando operações matemáticas', () => {
})
Isto
Vamos descrever as funções individuais, primeiramente a função soma, para isso usados o it, que significa Isto. Vai ficar assim:
import { soma, subtracao, divisao, multiplicacao } from "../math"
describe('Testando operações matemáticas', () => {
it('Deve retornar a soma de dois números', () => {
})
})
Criando a lógica de teste
Vou usar duas variáveis, a primeira nos da o valor que espero receber e a segunda o valor recebido, comparando as duas variáveis vai ficar claro se o teste foi um sucesso ou não.
Note que na "const recebido", usamos a função "soma" com os números 300 e 200, esperamos que o resultado desta função seja 500. Então colocamos o valor 500 na "const esperado".
import { soma, subtracao, divisao, multiplicacao } from "../math"
describe('Testando operações matemáticas', () => {
it('Deve retornar a soma de dois números', () => {
const esperado = 500;
const recebido = soma(300, 200);
})
})
Queremos que o Jest compare o valor "recebido" com o "esperado". Para fazer isso temos os matchers. Na documentação do Jest temos uma lista com vários tipos de matchers, vale apena consultar a documentação do Jest que nos ajuda bastante por ter a tradução em português.
Vou usar 2 tipos de machers mais comuns:
toBe – compara valores de uma forma superficial.
toEqual – compara não só os valores mais também outras propriedades, chamada de comparação profunda.
Vamos fazer a comparação usando o "expect" e usar o matcher "toBe"
import { soma, subtracao, divisao, multiplicacao } from "../math"
describe('Testando operações matemáticas', () => {
it('Deve retornar a soma de dois números', () => {
const esperado = 500;
const recebido = soma(300, 200);
expect(recebido).toBe(esperado);
})
})
Pronto,
seu primeiro teste esta configurado!Rodando o teste
No terminal do VS Code, na pasta raiz do seu projeto digite:
npm run test
PASS test/match.test.js – mostra que o teste passou e que o Jest encontrou nosso arquivo "math.test.js"
Mais abaixo vemos a descrição do nosso teste e o tempo que ele levou: 2 milissegundos.
Criando os testes restantes
Precisamos testar as funções subtração, divisão e multiplicação. Você pode fazer como desafio. Ou copie o código abaixo. Note que também usei o matcher "toEqual" apenas como exemplo.
import { soma, subtracao, divisao, multiplicacao } from "../math"
describe('Testando operações matemáticas', () => {
it('Deve retornar a soma de dois números', () => {
const esperado = 500;
const recebido = soma(300, 200);
expect(recebido).toBe(esperado);
})
it('Deve retornar a subtração de dois números', () => {
const esperado = 500;
const recebido = subtracao(2000, 1500);
expect(recebido).toEqual(esperado);
})
it('Deve retornar a multiplicação de dois números', () => {
const esperado = 25;
const recebido = multiplicacao(5, 5);
expect(recebido).toBe(esperado);
})
it('Deve retornar a divisão de dois números', () => {
const esperado = 30;
const recebido = soma(150, 5);
expect(recebido).toEqual(esperado);
})
})
Opções Watch e Coverage
O Jest também traz algumas opções interessantes para incrementar o nosso teste. A documentação do Jest traz muitas outras opções. Vou mostrar como usar 2 delas:
Watch – ele mantêm o teste aberto no terminal e a cada alteração no código, ele faz a atualização do teste em tempo real.
Coverage – cria uma interface HTML com os resultados do teste de uma forma mais atrativa
Fazendo a configuração no package.json
Adicione os scripts e salve o arquivo
CJS:
"scripts": {
"test": "node node_modules/jest/bin/jest.js",
"test:watch": "node node_modules/jest/bin/jest.js --watchAll",
"test:coverage": "node node_modules/jest/bin/jest.js --coverage"
},
ES6:
"scripts": {
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
"test:watch": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watchAll",
"test:coverage": "node --experimental-vm-modules node_modules/jest/bin/jest.js --coverage"
},
Rodando teste watch
digite no terminal :
npm run test:watch
resultado:
Agora cada vez que o código for salvo o teste será atualizado automaticamente, apertando "w" temos acesso ao menu com mais opções e apertando "q" saímos do modo watch.
Rodando teste coverage
digite no terminal:
npm run test:coverage
resultado:
Nosso teste ganha uma tabela com o nome dos arquivos e a cobertura dos testes em cada arquivo.
No caso 100% do arquivo está sendo coberto pelo nosso teste.
E onde esta a interface HTML?
Na pasta raiz do seu projeto foi criado uma pasta chamada "coverage",
dentro dela temos uma outra pasta "lcov-report"
Dentro dela temos o arquivo "index.html", devemos abrir ele no nosso navegador.
A interface HTML tem o visual mais agradável, um campo de busca e também podemos navegar dentro do código de cada arquivo.
Notamos que temos um campo "Branches" no nosso "coverage", esse "branch" não tem nada a ver com o branch do git. Na verdade a função dele é bem interessante e vale apena explicar neste artigo.
Branch x Estrutura Condicional
Quando falamos de estrutura condicional lembramos imediatamente do "if else".
E o "branch" tem tudo a ver com essa estrutura. Vamos ver na prática?
Preparando o ambiente
Vou criar um teste que possui um "if else" em seu contexto. Vamos criar na raiz do projeto o arquivo "array.js" e uma função que vai verificar se uma array esta vazia ou não, ela vai retornar "true" ou "false"
function verificaArrayVazia (array) {
if (array.length === 0) {
return true;
} else {
return false;
}
}
export default verificaArrayVazia;
Criando lógica de teste
Vou criar o arquivo de teste dentro da pasta "test", o nome do arquivo será "array.test.js".
O teste tem uma variável com uma array vazia e vamos testar se a função vai retornar "true".
import verificaArrayVazia from "../array"
describe('Testando funções de manipulação de arrays', () => {
it('Deve verificar se uma array esta vazia ou não', () => {
const arrayVazia = [];
const retorno = verificaArrayVazia(arrayVazia);
expect(retorno).toBe(true);
})
})
Rodando o teste coverage
digite no terminal:
npm run test:coverage
resultado:
Notamos que o teste passou e que foram testados os dois arquivos "array" e "math".
Porem o que mais chama nossa atenção é o "branch" do arquivo "array.js", ele está apenas com 50%, ou seja apenas 50% do codigo está sendo coberto pelo nosso teste.
Por quê?
Como usamos uma estrutura condicional IF, fizemos o teste apenas da metade da função. Faltou testar o ELSE concorda? Então para ter o branch em 100% precisamos adicionar o teste do else a nossa lógica.
Testando o eles
Voltando ao arquivo "array.test.js", adicione o teste do "ELSE" como desafio ou copie o código abaixo.
import verificaArrayVazia from "../array"
describe('Testando funções de manipulação de arrays', () => {
it('Deve verificar se uma array esta vazia ou não', () => {
const arrayVazia = [];
const esperado = true;
const retorno = verificaArrayVazia(arrayVazia);
expect(retorno).toBe(esperado);
})
it('Deve verificar se uma array tem conteúdo', () => {
const array = ['ola', 'mundo'];
const esperado = false;
const retorno = verificaArrayVazia(array);
expect(retorno).toBe(esperado);
})
})
Agora sim nosso "branch" será coberto em 100%.
Vamos refazer o teste "coverage"
npm run test:coverage
resultado:
Agora deu para entender como o "branch" e as condicionais estão ligadas.
Nem sempre vamos conseguir cobrir nosso código com testes em 100%, o importante mesmo é fazer os testes mais importantes com uma cobertura significativa.
Estou finalizando este artigo por aqui, mais vale lembrar que o assunto é extenso e fizemos testes bem simples.
Provavelmente farei mais artigos sobre testes no futuro. Abrangendo testes mais complexos. Não deixe de consultar a documentação do Jest.
Veja o vídeo no inicio deste artigo para ter mais detalhes.
Baixe os arquivos deste tutorial no GitHub.
E até a próxima!
Comentários
Postar um comentário