Menu

Catturare email nei test: tenere la CI fuori da Internet

Catturare email nei test significa puntare l'applicazione su un endpoint locale di ricezione, così le verifiche leggono il messaggio invece di attendere una casella.

Pubblicato

  • integrazione continua
  • posta di test
  • cattura locale

Catturare email nei test significa smettere di trattare la posta come qualcosa che lascia la macchina. Invece di lasciare che una build invii attraverso un fornitore pubblico e poi interroghi una casella nel mondo esterno, l’applicazione viene puntata su un endpoint di ricezione sull’host di build, e il test legge ciò che è stato consegnato. Il risultato è più veloce, funziona offline ed è immune agli incidenti del fornitore che altrimenti trasformano una suite verde in rossa.

Perché una pipeline non dovrebbe dipendere da un fornitore di posta

Un test che invia posta reale attraverso un servizio reale ha importato nel proprio risultato tutto ciò che è fragile di quel servizio. L’autenticazione può scadere, le quote possono esaurirsi, il fornitore può essere brevemente indisponibile, e nessuno di questi esiti dice qualcosa sul tuo codice. Peggio ancora, sono indistinguibili dai guasti che in realtà vuoi cogliere, così il team impara a rieseguire la pipeline invece di leggerla.

C’è un secondo costo facile da trascurare: una pipeline che invia posta reale deve sapere dove inviarla. Se quella destinazione è un indirizzo reale, ogni esecuzione consegna traffico di test a qualcuno. Puntare la build a un endpoint locale rimuove del tutto la questione, perché nulla lascia la rete.

Come funziona un endpoint di cattura locale?

Il meccanismo è lo stesso che usa qualsiasi server di posta. La tua applicazione viene configurata con un host e una porta del server di posta per la durata dell’esecuzione del test. Quell’host è l’interfaccia di loopback e la porta è quella che l’infrastruttura di test ha scelto per questa esecuzione, quindi nessun valore di configurazione deve essere affermato come un fatto sul mondo.

Una volta che l’applicazione consegna il messaggio, l’endpoint di cattura lo accetta, lo tiene in memoria o lo scrive su file e lo rende disponibile al test. Nulla viene inoltrato altrove.

Quella forma porta tre proprietà che rendono affidabili le asserzioni:

  • Il messaggio esiste prima che il test lo cerchi, perché la consegna è sincrona, quindi non c’è alcun ciclo di polling da sbagliare.
  • Il contenuto è esatto, incluse le intestazioni e la codifica, perché nulla l’ha riscritto in transito.
  • Il messaggio può essere riletto quante volte il test ne ha bisogno, perché viene memorizzato anziché consumato.

Cosa c’è davvero dentro un messaggio catturato?

Più del corpo, e le parti extra sono il luogo in cui vivono le asserzioni utili. Un messaggio catturato porta con sé le informazioni dell’involucro dalla consegna insieme al messaggio stesso, il che significa che un test può controllare da chi il messaggio dichiara di provenire, a quale indirizzo è stato inviato, l’oggetto, il tipo di contenuto e il corpo nella forma in cui la tua applicazione l’ha prodotto.

Questo conta perché la consegna non è l’oggetto del test. Il contenuto lo è. Una suite che verifica solo che un messaggio sia stato accettato passa felicemente mentre il modello visualizza un nome vuoto o il link punta all’ambiente sbagliato.

Un test che fallisce dovrebbe conservare il messaggio grezzo?

Sì, e dovrebbe conservarlo deliberatamente anziché per caso. Quando un’asserzione sul corpo fallisce, l’artefatto singolo più utile è il messaggio così com’è stato effettivamente prodotto. Senza di esso, il passo successivo è di solito riprodurre il guasto localmente a mano, che è precisamente il lavoro manuale che l’endpoint di cattura doveva rimuovere.

Due abitudini rendono utile l’artefatto. Allegalo all’esecuzione che fallisce anziché a una posizione condivisa, così che esecuzioni concorrenti non possano sovrascriversi. E trattalo come dato di test quando viene memorizzato: un messaggio catturato può contenere indirizzi e valori generati dall’esecuzione, e dovrebbe essere conservato con lo stesso programma breve del resto dell’output dell’esecuzione. Gli indirizzi usati in questo modo esistono per le asserzioni, mai come identità reali.

Quando invece ti serve una casella reale

Una cattura locale non può rispondere a domande che coinvolgono il mondo esterno. Se il test deve dimostrare che un messaggio sopravvive a un percorso di consegna reale, o che il sistema di una terza parte reagisce ad esso, allora qualcosa deve lasciare la macchina.

Per quei casi una casella usa e getta è spesso sufficiente: un indirizzo creato per l’esecuzione, letto una volta, scartato. La pagina della posta temporanea ne crea uno su richiesta, e poiché nessuno l’ha registrato, la casella parte vuota e non contiene altro che il traffico innescato dal test. Vale la pena tenere pulita la distinzione nella tua testa: la cattura locale serve per le asserzioni su ciò che la tua applicazione invia, e una casella reale serve per le asserzioni su ciò che arriva.

Per gli sviluppatori: porte, parallelismo e asserzioni

Quattro decisioni determinano se questa disposizione resta noiosa.

Legare l’endpoint di cattura soltanto all’interfaccia di loopback è la prima. Limita l’esposizione e rende ovvio che l’endpoint non è un servizio di posta per nulla al di fuori dell’esecuzione. Lascia che la porta provenga dall’ambiente anziché da una costante, così che due esecuzioni su una macchina non possano entrare in collisione.

Isolare le esecuzioni è la seconda. Dai a ogni esecuzione il proprio processo di endpoint, o almeno il proprio archivio, e dai a ogni caso il proprio indirizzo di destinatario. Una coda condivisa letta da diversi test in parallelo produce la classe di guasti più irritante che esista: un test che passa da solo e fallisce in una pipeline completa.

Verificare il contenuto anziché il tempo trascorso è la terza. Poiché la consegna è sincrona, non c’è nulla da attendere; un’attesa in questo tipo di test è il segno che qualcosa viene testato attraverso l’interfaccia sbagliata.

Fallire in modo rumoroso è la quarta. Quando un’asserzione su un messaggio fallisce, stampa o allega la parte che è stata confrontata. Un test che riporta solo una discrepanza, senza mostrare il messaggio che ha letto, rimanda la persona successiva alla riproduzione manuale.

Se il tuo percorso di cattura alimenta test che leggono codici brevi invece di corpi, il test OTP nelle suite end-to-end copre il lato del parsing, e l’approccio della casella catch-all copre cosa fare quando un ambiente ha davvero bisogno di un intero dominio invece di un singolo endpoint.

Prossimi passi

Trova l’unico test nella tua suite che invia posta attraverso un fornitore e conta quante volte ha fallito per ragioni non legate alla modifica sotto test. Poi dagli un endpoint locale per una singola esecuzione e confronta. Tieni il fornitore pubblico per tutto ciò che ha davvero bisogno di Internet aperto; il resto appartiene alla macchina che esegue i test.

Continua a leggere

Guide su Email temporanea (usa e getta / 10 minuti)