Introdução: Por que testar código TypeScript?
TypeScript é um superconjunto de JavaScript que adiciona tipagem estática. No entanto, os tipos não garantem a lógica correta do funcionamento da aplicação. Testar em TypeScript não é apenas uma "boa prática", mas uma necessidade para manter a qualidade do código, prevenir regressões e acelerar o desenvolvimento.
Neste artigo, vamos abordar os três principais níveis de teste: unit (unitário), integration (integração) e e2e (end-to-end). Você aprenderá quais ferramentas usar, verá exemplos de código e entenderá como construir uma estratégia de teste equilibrada para seu projeto TypeScript.
1. Testes Unitários em TypeScript
O que são testes unitários?
Testes unitários verificam módulos ou funções isoladas. Eles são executados rapidamente e não requerem dependências externas (banco de dados, rede, sistema de arquivos). O principal objetivo é garantir que cada pequena unidade de código funcione corretamente.
Ferramentas: Jest + ts-jest
O framework mais popular para testes unitários em TypeScript é o Jest com o transpilador ts-jest. Ele suporta mocks, spies, cobertura de código e se integra perfeitamente com TypeScript.
Exemplo de teste unitário
Suponha que temos uma função para calcular desconto:
// discount.tsexport function calculateDiscount(price: number, discountPercent: number): number { if (price < 0 || discountPercent < 0 || discountPercent > 100) { throw new Error('Invalid input'); } return price * (1 - discountPercent / 100);}Escrevemos o teste:
// discount.test.tsimport { calculateDiscount } from './discount';
describe('calculateDiscount', () => { it('should apply 10% discount correctly', () => { expect(calculateDiscount(1000, 10)).toBe(900); });
it('should throw error for negative price', () => { expect(() => calculateDiscount(-100, 10)).toThrow('Invalid input'); });
it('should handle 0% discount', () => { expect(calculateDiscount(500, 0)).toBe(500); });});Execução: npx jest. O Jest encontrará automaticamente todos os arquivos *.test.ts.
Melhores práticas para testes unitários
- Isole as dependências — use mocks (jest.mock) para módulos que acessam BD ou API.
- Teste casos limite — arrays vazios, null, números negativos.
- Siga o princípio FIRST — Fast, Isolated, Repeatable, Self-validating, Timely.
- Use describe/it — para uma estrutura de testes legível.
2. Testes de Integração (Integration Tests)
O que os testes de integração verificam?
Testes de integração verificam a interação de vários módulos: controller + service + banco de dados, ou endpoint de API + middleware. Eles são mais lentos que os testes unitários, mas fornecem mais confiança na correta conexão dos componentes.
Ferramentas: Supertest + Jest + BD in-memory
Para testar APIs Express/Node.js, frequentemente usamos Supertest (asserções HTTP) em conjunto com Jest. O banco de dados pode ser iniciado in-memory (por exemplo, mongodb-memory-server ou sqlite3).
Exemplo de teste de integração para API Express
Suponha que temos uma API REST simples para gerenciar usuários:
// app.tsimport express from 'express';import { userRouter } from './routes/userRoutes';
const app = express();app.use(express.json());app.use('/api/users', userRouter);
export { app };Teste com Supertest:
// user.integration.test.tsimport request from 'supertest';import { app } from '../app';
describe('POST /api/users', () => { it('should create a new user and return 201', async () => {
```