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 chaiEstrutura 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.jsonEscrevendo 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 test2. 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 nycAdicione um script para cobertura ao seu package.json:
"scripts": { "test": "mocha", "coverage": "nyc mocha" }Execute os testes com cobertura:
npm run coverageTestes 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.jsontest/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.jsExemplos 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.



Deixe um comentário