Mão na Massa: Seus Primeiros Testes Unitários (e o Truque dos Mocks!)
Escrevendo testes unitários básicos, usando Jest como exemplo, e entendendo Mocks/Stubs.
E aí, Dev! Chegou a hora de sujar as mãos (ou melhor, o teclado!) com testes. Nas aulas anteriores, a gente conversou sobre a importância de testar, desvendou a estratégia da Pirâmide e entendeu a mentalidade TDD/BDD. Tudo muito legal na teoria, né? Mas eu sei que a dúvida que fica é: "Beleza, Gabs, mas como eu escrevo essa bagaça na prática?".
Lembro da minha primeira vez escrevendo um teste unitário 'de verdade'. Parecia que eu tava escrevendo mais código pro teste do que pra função! E quando apareceu um negócio que falava com API? Quase desisti. 'Como eu testo isso sem chamar a API toda hora?!'. Foi aí que os Mocks entraram e... click. Entendi o poder de isolar as coisas.
É esse 'click' que quero te ajudar a ter hoje. Vamos pegar um exemplo simples, usando Jest (uma ferramenta super popular no mundo JavaScript), e desmistificar como escrever seus primeiros testes unitários e como usar "dublês" (Mocks/Stubs) pra lidar com dependências. Não é bicho de sete cabeças, prometo!
1. Preparando o Terreno: Por Que um Framework (Ex: Jest)?
Você até poderia escrever testes sem nenhuma ferramenta, mas seria como construir uma casa sem martelo e serrote: muito mais difícil e demorado. Frameworks de teste como Jest, PyTest (Python), RSpec (Ruby), JUnit (Java), etc., te dão:
Nesta aula, usaremos Jest como exemplo, mas os conceitos valem para qualquer framework.
2. Anatomia de um Teste Unitário Simples (com Jest)
Vamos começar com o mais básico do básico: testar uma função de soma.
O Código (Sua "Unidade"):
// arquivo: calculadora.js
function soma(a, b) {
return a + b;
}
module.exports = soma; // Exporta a função para poder ser usada no teste
O Teste (Verificando a Unidade):
// arquivo: calculadora.test.js
const soma = require('./calculadora'); // Importa a função a ser testada
describe('Calculadora - Função Soma', () => {
// 'describe' agrupa testes relacionados. É como um capítulo.
it('deve somar 2 + 2 e retornar 4', () => {
// 'it' (ou 'test') define um caso de teste específico.
const resultado = soma(2, 2); // 1. Executa a função
expect(resultado).toBe(4); // 2. Verifica (Assert) se o resultado é o esperado
});
it('deve somar números negativos corretamente', () => {
const resultado = soma(-5, 3);
expect(resultado).toBe(-2);
});
});
Descomplicando:
describe
: Agrupa testes com um tema comum. Ajuda na organização.it
ou test
: Descreve o que *um* teste específico deve fazer. A descrição deve ser clara!expect
: É a função de asserção. Você "espera" que algo (resultado
) seja (.toBe()
) alguma coisa (4
). O .toBe()
é um matcher – existem vários outros (ex: .toEqual()
, .toBeTruthy()
, .toContain()
).Simples, né? Isso é um teste unitário. Ele testa apenas a função soma
, de forma isolada.
3. O Problema: E Quando a Unidade Não Está Sozinha?
Raramente nossas funções são tão simples. Elas conversam com bancos de dados, chamam APIs externas, leem arquivos, usam outros módulos... Essas são as dependências.
Se o seu teste unitário realmente chama uma API externa ou acessa um banco de dados, ele deixa de ser puramente unitário. Por quê?
Como resolver isso? Com a mágica dos Mocks e Stubs!
4. Mocks & Stubs: Os Dublês do Seu Código
Pense em Mocks e Stubs como atores dublês. Eles entram em cena para substituir as dependências reais, permitindo que você teste sua unidade de forma isolada e previsível.
Exemplo Prático (com Jest - Mocking uma API):
Imagine uma função que busca dados de um usuário numa API:
O Código (com dependência):
// arquivo: userService.js
const axios = require('axios'); // Dependência externa (HTTP client)
async function buscarUsuario(userId) {
try {
const response = await axios.get(`https://api.exemplo.com/users/${userId}`);
return response.data;
} catch (error) {
console.error("Erro ao buscar usuário:", error);
return null;
}
}
module.exports = { buscarUsuario };
O Teste (com Mock):
// arquivo: userService.test.js
const axios = require('axios');
const { buscarUsuario } = require('./userService');
jest.mock('axios'); // 1. Diz ao Jest: "Ei, quando alguém pedir 'axios', entregue um dublê!"
describe('UserService - buscarUsuario', () => {
it('deve retornar os dados do usuário quando a API responde com sucesso', async () => {
const dadosUsuarioMock = { id: 1, name: 'Devly User' };
// 2. Configura o dublê: "Quando o 'get' do axios for chamado, finja que
// a API respondeu com sucesso e retorne estes dados"
axios.get.mockResolvedValue({ data: dadosUsuarioMock });
const usuario = await buscarUsuario(1); // 3. Chama a função (que usará o 'axios' mockado)
// 4. Verifica se a função retornou o que o dublê prometeu
expect(usuario).toEqual(dadosUsuarioMock);
// 5. (Opcional) Verifica se o dublê foi chamado do jeito certo
expect(axios.get).toHaveBeenCalledWith('https://api.exemplo.com/users/1');
});
it('deve retornar null quando a API responde com erro', async () => {
// Configura o dublê para simular um erro
axios.get.mockRejectedValue(new Error('API fora do ar'));
const usuario = await buscarUsuario(2);
expect(usuario).toBeNull();
});
});
O Pulo do Gato: Percebeu? Nós testamos a buscarUsuario
sem nunca chamar a API de verdade! Usamos o jest.mock('axios')
para interceptar a chamada e o mockResolvedValue
/ mockRejectedValue
para dizer ao dublê o que fazer. Isso é isolar a unidade e garantir um teste rápido e previsível.
5. O Mínimo Viável Que Abre Portas
Você não precisa ser um mestre em todos os tipos de mocks e frameworks amanhã. Mas entender o que é um teste unitário, saber escrever testes básicos para suas funções (especialmente as de lógica pura) e, crucialmente, entender o conceito de mocks para isolar dependências... isso já te coloca MUITO à frente de muitos devs.
É esse "mínimo viável" que as empresas gringas esperam ver. É o sinal de que você entende a importância da qualidade e sabe usar as ferramentas básicas para alcançá-la.
💊 Pílula Devly
Seu primeiro teste não precisa ser genial, só precisa existir. Comece simples, isole o que não é seu (mocks!), e construa confiança um expect
de cada vez. Cada teste verde é um passo a mais rumo a um código robusto (e ao seu salário em dólar!).