Testes em TypeScript: Unit, Integration, E2E — guia completo

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: Por que testar código TypeScript?

TypeScript é uma ferramenta poderosa que adiciona tipagem estática ao JavaScript, permitindo capturar erros em tempo de compilação. No entanto, mesmo o sistema de tipos mais rigoroso não garante que seu código funcionará corretamente em condições reais. Erros lógicos, tratamento incorreto de casos limite e problemas de integração de módulos permanecem fora do escopo do compilador. É aqui que os testes entram em ação.

Testar em TypeScript não é apenas verificar funções. É um processo abrangente que inclui três níveis principais: Unit (unitário), Integration (integração) e E2E (ponta a ponta). Cada um resolve um problema específico e, juntos, formam a "pirâmide de testes", garantindo a confiabilidade da aplicação.

Neste artigo, vamos explorar como escrever testes para TypeScript em todos os três níveis, usando ferramentas modernas: Jest, Supertest e Playwright. Você aprenderá quais erros esses testes ajudam a prevenir e como implementá-los em seu projeto.



Testes unitários: Verificação de módulos isolados

Testes unitários são a base da pirâmide. Eles testam funções, classes ou métodos individuais isolados de dependências externas (banco de dados, API, sistema de arquivos). O objetivo principal é garantir que cada "bloco" da sua aplicação funcione corretamente.



Ferramentas e configuração

O framework mais popular para testes unitários em TypeScript é o Jest. Ele oferece suporte nativo ao TypeScript através de ts-jest ou @swc/jest.

Instalação do Jest no projeto:

npm install --save-dev jest @types/jest ts-jestnpx ts-jest config:init


Exemplo de teste unitário

Vamos considerar uma função simples para calcular desconto:

// discount.tsexport function applyDiscount(price: number, discountPercent: number): number {  if (discountPercent < 0 || discountPercent > 100) {    throw new Error('A porcentagem de desconto deve estar entre 0 e 100');  }  return price - (price * discountPercent) / 100;}

Vamos escrever testes unitários cobrindo os cenários principais:

// discount.test.tsimport { applyDiscount } from './discount';

describe('applyDiscount', () => { it('deve aplicar corretamente um desconto de 20%', () => { expect(applyDiscount(100, 20)).toBe(80); });

it('deve retornar o preço original com desconto de 0%', () => { expect(applyDiscount(50, 0)).toBe(50); });

it('deve retornar 0 com desconto de 100%', () => { expect(applyDiscount(200, 100)).toBe(0); });

it('deve lançar erro para desconto negativo', () => { expect(() => applyDiscount(100, -10)).toThrow('A porcentagem de desconto deve estar entre 0 e 100'); });

it('deve lançar erro para desconto maior que 100%', () => { expect(() => applyDiscount(100, 150)).toThrow('A porcentagem de desconto deve estar entre 0 e 100'); });});

Importante: Testes unitários não devem acessar recursos externos. Em vez disso, use mocks para substituir dependências, por exemplo, com jest.mock().



Testes de integração: Interação entre módulos

Testes de integração verificam como diferentes partes do sistema funcionam juntas. Pode ser a interação entre um serviço e um banco de dados, um controlador e um repositório, ou entre microsserviços. Diferente dos testes unitários, aqui não isolamos os componentes completamente.



Exemplo: testando uma API REST

Suponha que temos uma aplicação Express com um endpoint. Para testar requisições HTTP, usamos Supertest.

// userController.tsimport { Router, Request, Response } from 'express';

interface User { id: number; name: string;}

const users: User[] = [{ id: 1, name: 'Alice' }];

Blogs

Book Recommendations