Tag: testing, unit-test, tdd, jest, vitest, mock, clean-code
Livello: intermedio
TL;DR: Verifica isolata delle singole unità logiche del codice per prevenire regressioni e guidare il design.
Testa la più piccola unità testabile dell'applicazione in completo isolamento dalle dipendenze esterne.
Segue il pattern AAA: Arrange (preparazione), Act (esecuzione), Assert (verifica del risultato atteso).
Deve rispettare i criteri FIRST: Fast, Independent, Repeatable, Self-validating, Timely.
I test unitari devono essere deterministici e privi di effetti collaterali verso rete, filesystem o database.
Si usano i test double (mock, stub, spy, dummy, fake) per sostituire i collaboratori esterni.
La copertura del codice (code coverage) misura le linee attraversate, non la correttezza logica delle asserzioni.
TDD applica il ciclo Red-Green-Refactor: scrivi il test prima del codice di produzione.
Testare il comportamento osservabile e le interfacce pubbliche anziché i dettagli implementativi interni.
Q: Qual è la differenza sostanziale tra uno Stub e un Mock?R: Uno stub fornisce risposte prefissate alle chiamate senza verificare le interazioni, mentre un mock registra le chiamate e verifica le asserzioni sul comportamento.
Q: Perché evitare di testare metodi o proprietà private?R: Testare i dettagli privati rende il test fragile al refactoring; preferisco testare l'interfaccia pubblica che ne esercita indirettamente la logica.
Q: Come approcci il codice legacy non coperto da test?R: Individuo i punti di giuntura, introduco prima test di caratterizzazione per congelare il comportamento attuale e poi rifattorizzo a piccoli passi.
Creare mock eccessivi che riflettono la struttura interna anziché il contratto dell'unità logica.
Inserire logica condizionale o loop all'interno dei test case.
Dipendenza dall'ordine di esecuzione dei test all'interno della suite.
Mancato reset dello stato globale o dei mock tra un test e l'altro.
Assert multipli non correlati che verificano comportamenti distinti nello stesso blocco.
```import { describe, it, expect, vi } from 'vitest';
describe('CalculatorService', () => {
it('should apply discount and round total correctly', () => {
// Arrange
const loggerMock = { log: vi.fn() };
const service = new CalculatorService(loggerMock);
// Act
const result = service.calculateTotal(100, 0.1);
// Assert
expect(result).toBe(90);
expect(loggerMock.log).toHaveBeenCalledWith('Calculated: 90');
});
});
```
[ ] Differenze architetturali tra Mockist e Classicist (London vs Detroit School)
[ ] Configurazione corretta dei fake timers per operazioni asincrone
[x] Principi FIRST e struttura AAA per la leggibilità dei test
[x] Isolamento delle chiamate I/O tramite dependency injection