Il problema dei test incompleti
Gli sviluppatori tendono a scrivere test per la logica che li preoccupa e a trascurare i piccoli dettagli. Il risultato è una copertura sufficiente per il “core” ma insufficiente per i casi limite che, spesso, sono proprio quelli che causano bug in produzione. Quando un test mancante avrebbe potuto individuare un errore prima della release, il costo di quel bug diventa evidente.
In precedenza Atlassian aveva già semplificato la generazione di test: un comando locale a un click chiedeva a un agente AI di scrivere i test per il file aperto nell’editor. Tuttavia, il processo dipendeva ancora dalla consapevolezza dello sviluppatore, che doveva notare la lacuna e decidere di avviare il comando.
Affidare il compito a un agente programmato
Per colmare questo vuoto è stato creato un agente schedulato, parte di una “pipeline agentica”. Ogni mattina, il pipeline analizza il repository, individua i file con copertura inferiore al target, genera i test mancanti e apre una pull request per la revisione.
Il risultato è stato sorprendente: in circa un mese, la copertura è passata dal 70 % all’82 %.
Partire da un singolo file
Invece di puntare all’intero repository, il team ha definito un compito molto più ristretto: su ogni esecuzione, l’agente sceglie un file TypeScript o React senza test o con copertura inferiore al target, scrive i test per quel file e verifica che le regole di sviluppo standard siano rispettate.
Questa limitazione ha due vantaggi fondamentali:
- Il revisore può comprendere rapidamente la modifica senza perdersi in un diff enorme.
- Un eventuale fallimento riguarda un solo obiettivo di test, non un’intera porzione di codice.
Prompt dettagliato per test di qualità
La prima versione chiedeva all’agente di coprire le istruzioni, i rami e le funzioni del file selezionato, includendo casi limite, percorsi di errore e regressioni potenziali. Quando il flusso si è dimostrato stabile, il target per file è stato aumentato modificando di una sola riga il file di prompt, revisionato come qualsiasi altra PR.
Come funziona il workflow schedulato
Il cuore della soluzione è una pipeline personalizzata di Bitbucket, con un prompt memorizzato nel repository. Di seguito una configurazione semplificata:
definitions:
agents:
test-coverage-maintainer:
provider: rovodev # o claude, codex
prompt: "!agent-prompts/improve-test-coverage.md"
pipelines:
custom:
improve-test-coverage:
- step:
name: Add one focused set of tests
auth:
system:
scopes:
- write:repository:bitbucket
- read:pullrequest:bitbucket
- write:pullrequest:bitbucket
script:
- npm ci
- npm run build
- agent: test-coverage-maintainer
L’unica riga dipendente dall’agente è provider, che supporta rovodev (default), claude e codex. Gli altri parametri – schedule, scope di autenticazione e file di prompt – rimangono invariati indipendentemente dal provider scelto.
La pipeline è stata programmata per essere eseguita ogni mattina feriale, così le PR arrivano quando gli sviluppatori sono ancora al loro posto.
Prompt di esempio
Un estratto del prompt usato in un repository già in grado di misurare la copertura:
Add the unit tests we skipped
Run the coverage command this repo already uses. Read the report.
Pick one source file below the per-file threshold in this file. Work on that one file only.
If none is below it, stop. Do not open a pull request.
Otherwise add unit tests for uncovered behavior, matching the style of
the tests already here. Leave production code unchanged.
Run the repo's style check, lint, and test suite.
If they fail and you cannot fix the tests, stop without a pull request.
When they pass, open one pull request. Say which code was uncovered
and what the new tests assert.
Le cinque fasi del flusso reale
1. Preparazione del repository
Prima di avviare l’agente, la pipeline esegue la normale fase di build (npm ci, npm run build) per fornire all’agente un ambiente di lavoro completo, evitando di dover reinstallare dipendenze ad ogni run.
2. Scelta di una lacuna
Il prompt obbliga l’agente a selezionare un solo file sorgente privo di test o con copertura sotto soglia, evitando di tentare una ristrutturazione dell’intera applicazione.
3. Scrittura e verifica dei test
L’agente itera finché i test generati passano e raggiungono il target di copertura per quel file. Durante il ciclo, vengono eseguiti il type‑checking, il lint e la suite di test del repository.
4. Controllo dei limiti
Il prompt vieta l’introduzione di nuove dipendenze o modifiche alla logica di business. L’agente deve riutilizzare i tipi esistenti, evitare suppressioni di lint e rimuovere mock superflui.
5. Apertura della pull request
Se tutti i controlli hanno successo, l’agente crea un branch e una PR con titolo prevedibile, collegamento all’item di lavoro e assegnazione dei revisori. La descrizione indica chiaramente quale codice era non coperto e cosa i nuovi test verificano.
Impatto sulla copertura e sulla revisione
In quattro settimane, i revisori hanno accettato circa 34 PR generate dall’agente, portando la copertura a livello di repository dal 70 % all’82 %.
Per evitare sovraccarichi, il workflow è stato progettato così:
- Ogni esecuzione apre al massimo una PR.
- La PR è limitata a un singolo file, quindi facilmente revisionabile in una singola sessione.
- Il titolo, l’item di lavoro e la descrizione sono standardizzati, così i revisori sanno subito cosa controllare.
- Se nessun file è sotto soglia, l’agente non apre alcuna PR, eliminando rumore inutile.
- Quando più revisori segnalano lo stesso problema, basta aggiornare il prompt una sola volta anziché commentare ogni PR.
Evoluzione dei test
Le prime PR hanno aggiunto file di test focalizzati per componenti singoli. Con il tempo, le esecuzioni successive hanno ampliato i test esistenti quando un componente continuava a presentare comportamenti non coperti.
Il pull request è diventato l’unità di lavoro utile: gli ingegneri potevano vedere quali comportamenti venivano testati, contestare mock inutili, rifiutare asserzioni fragili o richiedere casi più completi prima del merge.
Il prompt come parte integrante del sistema di test
Scrivere test Jest tramite l’agente è stato il passo più semplice; il vero valore è stato definire un prompt che decidesse se i test fossero degni di essere mantenuti.
Il prompt ha catturato dettagli solitamente applicati dallo sviluppatore senza essere scritti: dove posizionare i test, quali comandi eseguire, come strutturare gli import, quali scorciatoie non sono ammesse e quali parti del codice di produzione possono essere modificate.
Dopo le prime PR, si è scoperto che l’agente mockava moduli mai importati dal componente. I test passavano e la copertura aumentava, ma i mock erano solo rumore. È stata aggiunta una riga al prompt: “cancella qualsiasi mock che il test passa ancora senza”. Da allora il problema non è più ricomparso.
Il target di copertura è stato poi inasprito, la validazione di type e lint resa esplicita e il lavoro è rimasto limitato a un unico cambiamento revisionabile.
Consigli per altre squadre
Se desiderate replicare questo approccio, tenete presente questi punti:
- Iniziate piccolo. Affidate all’agente un compito ristretto, ad esempio “un file sotto soglia”.
- Definite un obiettivo chiaro. “Migliora la copertura” è troppo vago; “scrivi test per un file specifico” è una task concreta.
- Lasciate che il repository definisca “fatto”. Utilizzate gli stessi comandi di test, copertura, type‑check e lint che gli ingegneri usano localmente.
- Standardizzate il prompt. Aggiornatelo come parte di una PR, così il prossimo run seguirà automaticamente le nuove regole.
- Programmate le esecuzioni. Un orario mattutino garantisce che le PR arrivino quando i revisori sono attivi.
Seguendo questi principi, è possibile trasformare la copertura dei test da un’attività sporadica a un’abitudine quotidiana, migliorando la qualità del codice senza sovraccaricare i revisori.
