Testing Automatico: Unit, Integration ed E2E con Vitest e Playwright

THEJORD Team5 min di lettura
testingdevelopmentautomationquality

Testing automatico con Vitest e Playwright: unit, integration, E2E test. Guida pratica per scrivere test efficaci e automatizzare la qualità del codice.

Testing Automatico: Unit, Integration ed E2E con Vitest e Playwright

Introduzione al Testing Automatico

Il testing automatico è la base dello sviluppo software affidabile. I test catturano bug prima che raggiungano la produzione, documentano il comportamento atteso e ti permettono di refactorare con fiducia. Questa guida copre Unit, Integration ed E2E testing con Vitest e Playwright.

La Piramide dei Test

        /\
       /E2E\         Pochi, lenti, costosi
      /------\
     /Integr. \      Alcuni, velocità media
    /----------\
   /   Unit     \    Molti, veloci, economici
  /--------------\

Unit Test

Testano singole funzioni o componenti in isolamento:

  • Veloci (millisecondi)
  • Facili da scrivere e mantenere
  • Ottimi per logica di business

Integration Test

Testano come i moduli lavorano insieme:

  • Velocità media
  • Catturano bug di integrazione
  • Testano API, database, servizi

E2E Test

Testano l'intera applicazione come un utente:

  • Lenti ma realistici
  • Catturano bug di UI e flussi
  • Richiedono più manutenzione

Unit Testing con Vitest

Setup

npm install -D vitest

// vite.config.ts
export default {
  test: {
    globals: true,
    environment: 'jsdom'
  }
}

Scrivere Unit Test

// utils/math.ts
export function sum(a: number, b: number): number {
  return a + b;
}

export function divide(a: number, b: number): number {
  if (b === 0) throw new Error("Division by zero");
  return a / b;
}

// utils/math.test.ts
import { describe, it, expect } from 'vitest';
import { sum, divide } from './math';

describe('sum', () => {
  it('somma due numeri positivi', () => {
    expect(sum(2, 3)).toBe(5);
  });

  it('gestisce numeri negativi', () => {
    expect(sum(-1, 1)).toBe(0);
  });
});

describe('divide', () => {
  it('divide correttamente', () => {
    expect(divide(10, 2)).toBe(5);
  });

  it('lancia errore per divisione per zero', () => {
    expect(() => divide(10, 0)).toThrow("Division by zero");
  });
});

Testare Componenti React

// Button.test.tsx
import { render, screen, fireEvent } from '@testing-library/react';
import { Button } from './Button';

describe('Button', () => {
  it('renderizza il testo corretto', () => {
    render(<Button>Click me</Button>);
    expect(screen.getByText('Click me')).toBeInTheDocument();
  });

  it('chiama onClick quando cliccato', () => {
    const handleClick = vi.fn();
    render(<Button onClick={handleClick}>Click</Button>);
    fireEvent.click(screen.getByText('Click'));
    expect(handleClick).toHaveBeenCalledTimes(1);
  });
});

Integration Testing

Testare API con Vitest

// api/users.test.ts
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { createServer } from '../server';

let server;

beforeAll(async () => {
  server = await createServer();
});

afterAll(() => {
  server.close();
});

describe('API Users', () => {
  it('GET /api/users ritorna lista utenti', async () => {
    const response = await fetch('http://localhost:3000/api/users');
    const data = await response.json();
    
    expect(response.status).toBe(200);
    expect(Array.isArray(data)).toBe(true);
  });

  it('POST /api/users crea nuovo utente', async () => {
    const response = await fetch('http://localhost:3000/api/users', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ name: 'Mario', email: 'mario@test.it' })
    });
    
    expect(response.status).toBe(201);
  });
});

E2E Testing con Playwright

Setup

npm install -D @playwright/test
npx playwright install

Scrivere E2E Test

// tests/login.spec.ts
import { test, expect } from '@playwright/test';

test.describe('Login', () => {
  test('login con credenziali valide', async ({ page }) => {
    await page.goto('/login');
    
    await page.fill('[name="email"]', 'user@example.com');
    await page.fill('[name="password"]', 'password123');
    await page.click('button[type="submit"]');
    
    await expect(page).toHaveURL('/dashboard');
    await expect(page.locator('h1')).toContainText('Benvenuto');
  });

  test('mostra errore con credenziali invalide', async ({ page }) => {
    await page.goto('/login');
    
    await page.fill('[name="email"]', 'wrong@example.com');
    await page.fill('[name="password"]', 'wrongpassword');
    await page.click('button[type="submit"]');
    
    await expect(page.locator('.error')).toBeVisible();
  });
});

Best Practices

  • Test Behavior, Not Implementation: Testa cosa fa, non come
  • Un Assert per Test: Mantieni i test focalizzati
  • Nomi Descrittivi: "dovrebbe mostrare errore quando email invalida"
  • AAA Pattern: Arrange, Act, Assert
  • Evita Test Flaky: Usa wait appropriati, evita timing hardcoded

Conclusione

Una buona strategia di testing combina tutti e tre i livelli: molti unit test veloci, alcuni integration test, e pochi E2E critici. Vitest e Playwright sono strumenti moderni e potenti che rendono il testing più piacevole e produttivo.