Testing — Cheat Sheet

Tag: testing, unit-test, integration-test, e2e, jest, playwright, tdd

Livello: intermedio

TL;DR: Strategie, piramide dei test e pattern di automazione per garantire affidabilita' del codice e prevenire regressioni in produzione.

Concetti chiave

Piramide dei test: base ampia di unit test, livello intermedio di integrazione, vertice contenuto di E2E.

Unit test: verifica componenti o funzioni pure in isolamento, con mock delle dipendenze esterne.

Test di integrazione: validazione dell'interazione reale tra moduli, database, middleware e API interne.

Test End-to-End: simulazione dei flussi utente completi su interfaccia reale o browser headless.

TDD (Test-Driven Development): ciclo Red-Green-Refactor basato su specifica dei requisiti prima dell'implementazione.

Code coverage: metrica quantitativa di linee, rami e funzioni eseguite durante la suite di test.

Test doppi: distinzione operativa tra dummy, stub, spy, mock e fake object.

Regression testing: esecuzione sistematica della suite a ogni pipeline CI per prevenire guasti pregressi.

Smoke test: controlli minimi di sanita' per verificare l'avvio e la stabilita' post-deploy del sistema.

Flaky test: test non deterministici causati da race condition, timing errati o dipendenze condivise.

Domande tipiche e risposte pronte

Q: Come approcci la piramide dei test in un'applicazione moderna?R: Concentro la maggior parte degli sforzi su unit test veloci e test di integrazione affidabili. Mantengo i test E2E focalizzati esclusivamente sui flussi di business critici per evitare lentezza ed instabilita' nella pipeline CI/CD.

Q: Quando preferisci un mock rispetto a un database o servizio reale?R: Uso mock negli unit test per isolare la logica pura e simulare errori rari o timeout di rete. Nei test di integrazione preferisco sempre database effettivi su container effimeri per testare query, vincoli e transazioni reali.

Q: Come gestisci e riduci i flaky test in CI?R: Rimuovo attese arbitrarie usando polling condizionale su stato ed eventi del DOM o backend. Isolo lo stato dei dati tra ogni test per eliminare contaminazioni e dipendenze sequenziali non deterministiche.

Insidie e errori comuni

Testare dettagli implementativi privati invece del comportamento e dell'interfaccia pubblica.

Presenza di race condition causate dall'uso di sleep fisso anziche' attese esplicite di eventi.

Dipendenza dall'ordine di esecuzione dei test dovuta a stato globale condiviso o database non ripulito.

Mocking eccessivo che trasforma i test in specchi del codice senza validare scenari reali.

Inseguire il 100% di coverage ignorando la qualita' effettiva delle asserzioni sui casi limite.

Snippet e comandiTypeScript

// Pattern AAA (Arrange, Act, Assert) con isolamento dipendenze
describe('UserService.register', () => {
  it('should throw error when user already exists', async () => {
    const userRepositoryMock = {
      findByEmail: jest.fn().mockResolvedValue({ id: '1', email: 'test@example.com' }),
      save: jest.fn(),
    };
    const sut = new UserService(userRepositoryMock);

    await expect(sut.register('test@example.com', 'pwd')).rejects.toThrow(UserExistsException);
    expect(userRepositoryMock.save).not.toHaveBeenCalled();
  });
});

Bash

# Esecuzione mirata con coverage in Jest
npm test -- --coverage --runInBand --detectOpenHandles

Da ripassare

[ ] Pattern Arrange-Act-Assert e Clean Architecture nei test

[ ] Strategie di mock parziale con SpyOn e factory functions

[ ] Configurazione di database transazionali per test di integrazione

[ ] Attese esplicite e selettori accessibili (byRole) in Playwright e Testing Library

[ ] Rilevamento e quarantena dei flaky test nei workflow GitHub Actions

Jarvis Interviews
Jarvis