Testes Unitários em Node.js

Testes Unitários em Node.js

Os testes unitários desempenham um papel crucial no desenvolvimento de software, permitindo que os desenvolvedores garantam a qualidade e a robustez de seus códigos. Em ambientes Node.js, a realização de testes unitários é uma prática comum para validar o funcionamento de funções e módulos. Neste artigo, exploraremos exemplos práticos de testes unitários em três níveis: básico, intermediário e avançado, utilizando as bibliotecas mais comuns como Mocha e Chai.

1. Configurando o Ambiente e Escrevendo Testes Simples com Mocha e Chai

Instalando as Dependências:

O primeiro passo é instalar as bibliotecas de teste Mocha e Chai.

 npm install mocha chai

Estrutura Básica de Diretórios:

Crie uma estrutura básica de diretórios para organizar seus testes.

 |-- meu-projeto |-- src |-- minha-funcao.js |-- test |-- minha-funcao.test.js |-- package.json

Escrevendo Testes Simples:

Vamos criar uma função simples em src/minha-funcao.js e escrever testes para ela em test/minha-funcao.test.js.

src/minha-funcao.js:

 function somar(a, b) { return a + b; } module.exports = somar;

test/minha-funcao.test.js:

 const chai = require('chai'); const somar = require('../src/minha-funcao'); const expect = chai.expect; describe('Minha Função de Somar', () => { it('Deve somar dois números corretamente', () => { const resultado = somar(3, 4); expect(resultado).to.equal(7); }); it('Deve somar números negativos corretamente', () => { const resultado = somar(-2, -5); expect(resultado).to.equal(-7); }); });

Executando os Testes:

Adicione um script ao seu package.json para executar os testes.

 "scripts": { "test": "mocha" }

Execute os testes:

 npm test

2. Utilizando Hooks e Testando Assincronicidade

Hooks do Mocha:

Os hooks do Mocha permitem executar código antes ou depois dos testes. Vamos adicionar um hook beforeEach para inicializar variáveis antes de cada teste.

test/minha-funcao.test.js:

 const chai = require('chai'); const somar = require('../src/minha-funcao'); const expect = chai.expect; describe('Minha Função de Somar', () => { let resultado; beforeEach(() => { resultado = somar(3, 4); }); it('Deve somar dois números corretamente', () => { expect(resultado).to.equal(7); }); it('Deve somar números negativos corretamente', () => { const resultadoNegativo = somar(-2, -5); expect(resultadoNegativo).to.equal(-7); }); });

Testando Assincronicidade com Mocha e Chai:

Adaptaremos a função para suportar operações assíncronas e testaremos sua assincronicidade.

src/minha-funcao.js:

 function somarAssincrono(a, b, callback) { setTimeout(() => { callback(null, a + b); }, 1000); } module.exports = somarAssincrono;

test/minha-funcao.test.js:

 describe('Minha Função de Somar Assíncrona', () => { it('Deve somar dois números assincronamente', (done) => { somarAssincrono(3, 4, (err, resultado) => { expect(resultado).to.equal(7); done(); }); }); });

3. Cobertura de Código e Testes de Integração

Adicionando Cobertura de Código com Istanbul:

Vamos adicionar a capacidade de medir a cobertura de código usando o pacote istanbul.

 npm install nyc

Adicione um script para cobertura ao seu package.json:

 "scripts": { "test": "mocha", "coverage": "nyc mocha" }

Execute os testes com cobertura:

 npm run coverage

Testes de Integração:

Para testes de integração, vamos criar um arquivo separado.

 |-- meu-projeto |-- src |-- minha-funcao.js |-- test |-- minha-funcao.test.js |-- integracao.test.js |-- package.json

test/integracao.test.js:

 const chai = require('chai'); const somar = require('../src/minha-funcao'); const expect = chai.expect; describe('Testes de Integração', () => { it('Deve somar dois números corretamente (Integração)', () => { const resultado = somar(3, 4); expect(resultado).to.equal(7); }); it('Deve somar números negativos corretamente (Integração)', () => { const resultadoNegativo = somar(-2, -5); expect(resultadoNegativo).to.equal(-7); }); });

Execute os testes de integração:

 npm run test integracao.test.js

Exemplos Práticos

Escrevendo Testes Unitários Eficazes em Node.js

Escrever testes unitários é uma prática essencial para garantir a robustez e a confiabilidade do código em projetos Node.js. Neste artigo, exploraremos exemplos práticos de testes unitários em diferentes cenários, utilizando as bibliotecas populares Mocha e Chai. Vamos abordar desde testes básicos até casos mais complexos, demonstrando como essa prática pode ser integrada facilmente ao seu fluxo de desenvolvimento.

1. Testando uma Função Simples:

Considere a seguinte função simples que soma dois números:

src/minha-funcao.js:

 function somar(a, b) { return a + b; } module.exports = somar;

test/minha-funcao.test.js:

 const chai = require('chai'); const somar = require('../src/minha-funcao'); const expect = chai.expect; describe('Função de Somar', () => { it('Deve somar dois números corretamente', () => { const resultado = somar(3, 4); expect(resultado).to.equal(7); }); it('Deve somar números negativos corretamente', () => { const resultadoNegativo = somar(-2, -5); expect(resultadoNegativo).to.equal(-7); }); });

Neste exemplo, utilizamos a biblioteca Chai para expressar as expectativas dos resultados. O método expect é uma maneira clara e legível de verificar se os resultados esperados são iguais aos resultados reais.

2. Trabalhando com Funções Assíncronas:

Agora, vamos considerar uma função assíncrona que realiza uma operação após um intervalo de tempo:

src/minha-funcao.js:

 function operacaoAssincrona(callback) { setTimeout(() => { callback('Operação concluída'); }, 1000); } module.exports = operacaoAssincrona;

test/minha-funcao.test.js:

 const chai = require('chai'); const operacaoAssincrona = require('../src/minha-funcao'); const expect = chai.expect; describe('Operação Assíncrona', () => { it('Deve concluir a operação assíncrona com sucesso', (done) => { operacaoAssincrona((resultado) => { expect(resultado).to.equal('Operação concluída'); done(); }); }); });

Neste caso, utilizamos o argumento done para indicar ao Mocha que a execução do teste assíncrono foi concluída.

3. Testando Exceções:

Vamos considerar uma função que lança uma exceção para tratar casos específicos:

src/minha-funcao.js:

 function dividir(a, b) { if (b === 0) { throw new Error('Divisão por zero não permitida'); } return a / b; } module.exports = dividir;

test/minha-funcao.test.js:

 const chai = require('chai'); const dividir = require('../src/minha-funcao'); const expect = chai.expect; describe('Função de Dividir', () => { it('Deve dividir dois números corretamente', () => { const resultado = dividir(6, 2); expect(resultado).to.equal(3); }); it('Deve lançar uma exceção ao tentar dividir por zero', () => { expect(() => dividir(6, 0)).to.throw('Divisão por zero não permitida'); }); });

Aqui, utilizamos a função throw do Chai para verificar se a exceção é lançada corretamente.

4. Mocks e Espiões para Funções Externas:

Suponhamos que temos uma função que faz uma requisição HTTP externa. Para testar essa função sem realizar chamadas reais à API, podemos usar mocks e espionar o comportamento da função externa:

src/minha-funcao.js:

 const axios = require('axios'); async function obterDadosDaAPI() { const resposta = await axios.get('https://api.example.com/dados'); return resposta.data; } module.exports = obterDadosDaAPI;

test/minha-funcao.test.js:

 const chai = require('chai'); const sinon = require('sinon'); const axios = require('axios'); const obterDadosDaAPI = require('../src/minha-funcao'); const expect = chai.expect; describe('Função de Obter Dados da API', () => { it('Deve obter dados da API corretamente', async () => { // Criar um "espião" para a função axios.get const axiosGetSpy = sinon.spy(axios, 'get'); // Chamar a função que estamos testando await obterDadosDaAPI(); // Verificar se a função axios.get foi chamada corretamente expect(axiosGetSpy.calledOnce).to.be.true; // Restaurar a função original após o teste axios.get.restore(); }); });

Neste exemplo, utilizamos a biblioteca sinon para criar um espião da função axios.get, permitindo-nos verificar se ela foi chamada corretamente durante o teste.

Estes exemplos práticos ilustram como escrever testes unitários eficazes em projetos Node.js. Testar desde funções simples até cenários mais complexos, incluindo funções assíncronas, tratamento de exceções e uso de mocks, é essencial para garantir a qualidade do código.

Ao incorporar a prática de testes unitários em seu fluxo de desenvolvimento, você constrói uma base sólida para manutenibilidade e evolução do seu código.

Conclusão: Elevando seus Testes Unitários em Node.js

Este guia prático abrangeu desde os fundamentos até técnicas avançadas de testes unitários em Node.js. Os testes são cruciais para garantir a qualidade do software, e com as ferramentas certas, como Mocha, Chai e Istanbul, é possível criar uma suíte de testes robusta.

Aplique esses princípios em seus projetos, explore outras técnicas como spies e mocks, e busque sempre melhorar a cobertura de código. Testes unitários não são apenas uma prática de desenvolvimento; são um investimento no sucesso e na manutenibilidade de seus projetos Node.js.

Avatar de Emir Freiberger

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Liyana Parker

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.