Przypadki testowe generowane przez sztuczną inteligencję: wykorzystanie LLM jako osoby piszącej automatyczne testy
Pisanie testów jest nudne, czasochłonne i odkładające się na później. Ile razy widziałeś PR bez ani jednego nowego testu, dlaczego „dodałem do backlogu”? LLM to zmieniają scenariusz: GitHub Copilot, Claude i GPT-4 mogą generować przypadki testowe o zaskakującej jakości zaczynając od kodu źródłowego, historii użytkowników lub specyfikacji API – skracając czas pisania testów o 40-60% i obniżenie bariery psychologicznej skłaniającej do ich pomijania.
Ale nie wystarczy poprosić sztuczną inteligencję o „napisanie testów” i ślepo z nich skorzystać. Ten przewodnik pokazuje ustrukturyzowany przepływ pracy umożliwiający generowanie wysokiej jakości testów, walidację ich i integrowanie z potokiem CI.
Czego się nauczysz
- Podpowiadanie strategii generowania skutecznych przypadków testowych
- Przepływ pracy GitHub Copilot do testowania jednostkowego z kodu źródłowego
- Generowanie testów na podstawie historii użytkowników i specyfikacji BDD
- Jak walidować jakość testów generowanych przez sztuczną inteligencję
- Integracja z testowaniem mutacji w celu weryfikacji rzeczywistej wartości
- Ograniczenia i ryzyko: gdy testy AI nie wystarczą
Problem z testami pisanymi przez sztuczną inteligencję bez weryfikacji
Zanim przejdziemy do przepływu pracy, krytyczne ostrzeżenie: LLM generują testy, które przechodzą
łatwo, ale niekoniecznie, przetestować właściwe zachowanie. Najpopularniejszym wzorem jest tzw
„test fantomowy” — test, który to sprawdza result !== null zamiast sprawdzać
prawdziwą wartość.
// ESEMPIO DI TEST AI GENERATO SCARSO (da evitare)
// Copilot ha generato questo — sembra un test, ma non verifica nulla di utile
import { calculateDiscount } from './pricing';
describe('calculateDiscount', () => {
it('should return a value', () => {
const result = calculateDiscount(100, 'PROMO10');
expect(result).toBeDefined(); // INUTILE: non verifica il valore corretto
expect(result).not.toBeNull(); // INUTILE: solo dice "non e null"
expect(typeof result).toBe('number'); // DEBOLE: non verifica che sia 90
});
});
// ESEMPIO DI TEST AI GENERATO BUONO (con prompt corretto)
describe('calculateDiscount', () => {
it('applica sconto PROMO10 del 10% sul prezzo base', () => {
expect(calculateDiscount(100, 'PROMO10')).toBe(90);
});
it('restituisce il prezzo originale per codice non valido', () => {
expect(calculateDiscount(100, 'INVALID')).toBe(100);
});
it('applica sconto massimo del 50% anche per codici piu generosi', () => {
expect(calculateDiscount(100, 'SUPER80')).toBe(50); // cap al 50%
});
it('gestisce prezzi a zero senza errori', () => {
expect(calculateDiscount(0, 'PROMO10')).toBe(0);
});
it('lancia errore per prezzi negativi', () => {
expect(() => calculateDiscount(-10, 'PROMO10')).toThrow(RangeError);
});
});
Skuteczne monitowanie dla GitHub Copilot
Jakość wygenerowanych testów zależy bezpośrednio od jakości podpowiedzi. Oto strategie bardziej skuteczne:
// STRATEGIA 1: Commento contestuale nel file di test
// Il commento guida Copilot nel generare test completi
// src/utils/string-validator.ts
export function validateEmail(email: string): boolean {
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return regex.test(email);
}
export function validatePassword(password: string): {
valid: boolean;
errors: string[];
} {
const errors: string[] = [];
if (password.length < 8) errors.push('Minimo 8 caratteri');
if (!/[A-Z]/.test(password)) errors.push('Almeno una maiuscola');
if (!/[0-9]/.test(password)) errors.push('Almeno un numero');
if (!/[!@#$%]/.test(password)) errors.push('Almeno un carattere speciale');
return { valid: errors.length === 0, errors };
}
// src/utils/string-validator.test.ts
// Test per validateEmail e validatePassword.
// Coprire: email valide, email non valide (mancano @, dominio, TLD),
// password valida, password troppo corta, password senza maiuscola,
// senza numero, senza speciale, stringa vuota, valori limite.
// Usare describe nested per raggruppare casi validi e invalidi.
// I test devono essere deterministici, no mocks necessari.
import { validateEmail, validatePassword } from './string-validator';
describe('validateEmail', () => {
describe('email valide', () => {
test.each([
['user@example.com'],
['user.name+tag@company.co.uk'],
['123@numbers.org'],
])('%s deve essere valida', (email) => {
expect(validateEmail(email)).toBe(true);
});
});
describe('email non valide', () => {
test.each([
['not-an-email'],
['missing@'],
['@nodomain.com'],
['spaces in@email.com'],
[''],
])('%s deve essere non valida', (email) => {
expect(validateEmail(email)).toBe(false);
});
});
});
describe('validatePassword', () => {
it('password valida supera tutti i controlli', () => {
const result = validatePassword('SecureP@ss1');
expect(result.valid).toBe(true);
expect(result.errors).toHaveLength(0);
});
it('password troppo corta produce errore specifico', () => {
const result = validatePassword('Ab1@');
expect(result.valid).toBe(false);
expect(result.errors).toContain('Minimo 8 caratteri');
});
});
Generowanie na podstawie historii użytkowników z Claudem
Claude jest szczególnie skuteczny w przekształcaniu historii użytkowników w ustrukturyzowane przypadki testowe, w tym przypadki brzegowe, o których programiści zwykle zapominają.
"""
Prompt per Claude: Generazione test da User Story
"""
user_story = """
User Story: Come utente registrato, voglio aggiungere prodotti al carrello
in modo da poter procedere all'acquisto.
Criteri di accettazione:
- L'utente puo aggiungere un prodotto disponibile al carrello
- Il contatore nel header si aggiorna immediatamente
- Non si possono aggiungere prodotti esauriti
- La quantita massima per prodotto e 10
- Un prodotto gia nel carrello aumenta la quantita (non crea duplicato)
- I prodotti nel carrello persistono dopo refresh della pagina
"""
prompt = f"""Sei un QA engineer esperto in BDD e test automation.
Data la seguente user story e criteri di accettazione, genera:
1. Casi di test Playwright in TypeScript per i test E2E
2. Unit test per la funzione addToCart(productId, quantity) in Vitest
3. Test cases in formato Gherkin (BDD) per la documentazione
Per ogni test specifica:
- Scenario (nome descrittivo)
- Precondizioni
- Azioni
- Risultato atteso
Includi casi happy path, edge cases e casi di errore.
User Story:
{user_story}
Genera i test nel formato richiesto, con commenti che spiegano il
rationale di ogni caso di test."""
# Risposta Claude genera 15-20 test cases strutturati con Playwright + Vitest + Gherkin
# Esempio output Claude in Gherkin
Feature: Aggiunta prodotti al carrello
Background:
Given l'utente e autenticato
And il catalogo prodotti e disponibile
Scenario: Aggiunta prodotto disponibile
When l'utente clicca "Aggiungi al carrello" sul prodotto "Laptop Pro X"
Then il carrello contiene 1 unita di "Laptop Pro X"
And il contatore nell'header mostra "1"
Scenario: Prodotto gia nel carrello
Given il carrello contiene 1 unita di "Laptop Pro X"
When l'utente clicca "Aggiungi al carrello" sullo stesso prodotto
Then il carrello contiene 2 unita di "Laptop Pro X"
And non viene creato un record duplicato
Scenario: Tentativo aggiunta prodotto esaurito
Given il prodotto "Tablet Z" ha disponibilita 0
Then il bottone "Aggiungi al carrello" per "Tablet Z" e disabilitato
Scenario: Limite quantita massima
Given il carrello contiene 10 unita di "Mouse Wireless"
When l'utente tenta di aggiungere un'altra unita
Then viene mostrato il messaggio "Quantita massima raggiunta (10)"
And la quantita rimane 10
Kompletny przepływ pracy: od kodu do zweryfikowanych testów
// Workflow in 5 step per test AI-generated di qualita
// STEP 1: Genera i test
// Prompt: "Genera test completi per questo servizio con casi happy path,
// edge cases, casi di errore. Usa Vitest e TypeScript."
// [AI genera tests/payment.service.test.ts]
// STEP 2: Esegui i test generati
// npm run test -- tests/payment.service.test.ts
// ATTESO: tutti passano (se l'implementazione e corretta)
// STEP 3: Verifica mutation score
// npx stryker run -- solo sui file modificati
// TARGET: mutation score > 60% sui test AI-generated
// STEP 4: Review manuale
const REVIEW_CHECKLIST = `
[ ] I test coprono i criteri di accettazione?
[ ] I test verificano il comportamento (non l'implementazione)?
[ ] Ci sono edge cases mancanti? (null, undefined, stringhe vuote, valori limite)
[ ] I test sono deterministici? (no Date.now(), no Math.random() senza mock)
[ ] I test sono isolati? (no dipendenze tra test)
[ ] I nomi dei test descrivono il comportamento atteso?
[ ] I test falliscono correttamente se implementazione e errata?
`;
// STEP 5: Aggiungi test mancanti
// Usa mutation report per identificare mutanti non uccisi
// Aggiungi test mirati per i mutanti sopravvissuti
Zweryfikuj testy AI za pomocą testów mutacji
Najbardziej niezawodnym sposobem sprawdzenia, czy testy generowane przez sztuczną inteligencję mają rzeczywistą wartość, jest przeprowadzić na nich testy mutacyjne:
// stryker.config.js — configurazione per analizzare test AI-generated
/** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */
module.exports = {
testRunner: 'vitest',
coverageAnalysis: 'perTest',
mutate: [
// Muta solo i file per cui stiamo analizzando i test
'src/services/payment.service.ts',
'src/utils/pricing.ts'
],
vitest: {
configFile: 'vitest.config.ts'
},
thresholds: {
high: 80,
low: 60,
break: 50 // Fallisce la build se mutation score scende sotto 50%
},
reporters: ['html', 'json', 'clear-text'],
htmlReporter: {
fileName: 'reports/mutation-report.html'
}
};
Zagrożenia i ograniczenia generowania testów AI
- Testy testujące implementację: AI ma tendencję do powielania logiki kodu w testach zamiast weryfikować zachowanie. Przejrzyj testy, jak wyglądają „lustro” kodu źródłowego
- Brak wiedzy domenowej: AI nie zna reguł biznesowych konkretnej domeny. Należy napisać lub przejrzeć krytyczne testy logiki biznesowej od programisty z kontekstem
- Fałszywe zapewnienie: Wygenerowane testy, które przechodzą pomyślnie, nie oznaczają testów przydatnych. Zawsze wykonuj testy mutacji przed rozważeniem pełnego pokrycia
- Halucynacje w urządzeniach: AI może generować dane testowe, które wyglądają jak ważne, ale nie są (daty niemożliwe, liczby spoza zakresu, e-maile formalnie ważne, ale semantycznie niepoprawne)
Wnioski
Generowanie testów AI jest potężnym narzędziem, jeśli jest używane prawidłowo: przyspiesza pisanie szablonu, generuje przypadki brzegowe, o których łatwo zapomnieć i obniża barierę psychologia do testów. Wymaga to jednak przepływu pracy w zakresie walidacji – testowania i przeglądu mutacji manualnie — aby mieć pewność, że wygenerowane testy rzeczywiście mają wartość.
Praktyczna zasada: wykorzystuje sztuczną inteligencję do generowania 80% standardowych i oczywistych przypadków; Piszesz 20%, które wymagają znajomości domeny.







