Menu

E-mail vastleggen in tests — houd CI van het publieke internet

Leg e-mail vast in tests door de applicatie op een lokaal ontvangstpunt te richten, zodat asserties het bericht lezen in plaats van op een postvak te wachten.

Gepubliceerd

  • continue integratie
  • testmail
  • lokale capture

E-mail vastleggen in tests betekent ophouden mail te behandelen als iets dat de machine verlaat. In plaats van een build via een publieke provider te laten verzenden en vervolgens een postvak in de buitenwereld te pollen, wordt de applicatie op een ontvangstpunt op de buildhost gericht, en de test leest wat er is overgedragen. Het resultaat is sneller, offline mogelijk en immuun voor de incidenten bij providers die anders een groene suite rood maken.

Waarom een pipeline niet van een mailprovider afhankelijk zou moeten zijn

Een test die echte mail via een echte dienst verzendt, heeft alles wat fragiel is aan die dienst in zijn eigen resultaat geïmporteerd. Authenticatie kan verlopen, quota kunnen uitgeput raken, de provider kan even onbeschikbaar zijn, en geen van die uitkomsten zegt iets over je code. Erger nog, ze zijn niet te onderscheiden van de storingen die je juist wilt opvangen, dus het team leert de pipeline opnieuw te draaien in plaats van hem te lezen.

Er is een tweede kostenpost die makkelijk over het hoofd wordt gezien: een pipeline die echte mail verzendt, moet worden verteld waarheen. Als die bestemming een echt adres is, bezorgt elke run testverkeer bij iemand. De build op een lokaal eindpunt richten haalt de vraag volledig weg, omdat er niets het netwerk verlaat.

Hoe werkt een lokaal opvangpunt?

Het mechanisme is hetzelfde als dat van elke mailserver. Je applicatie wordt voor de duur van de testrun geconfigureerd met een host en poort van een mailserver. Die host is de loopbackinterface en de poort is degene die de testharnes voor deze run heeft gekozen, dus geen enkele configuratiewaarde hoeft als een feit over de wereld te worden geassert.

Zodra de applicatie het bericht overdraagt, accepteert het opvangpunt het, houdt het in het geheugen of schrijft het naar een bestand, en stelt het beschikbaar aan de test. Er wordt nergens iets doorgestuurd.

Die vorm brengt drie eigenschappen mee die asserties betrouwbaar maken:

  • Het bericht bestaat voordat de test ernaar zoekt, omdat de overdracht synchroon is, dus er is geen poll-lus die fout kan gaan.
  • De inhoud is exact, inclusief headers en codering, omdat niets die onderweg heeft herschreven.
  • Het bericht kan zo vaak opnieuw worden gelezen als de test nodig heeft, omdat het wordt opgeslagen in plaats van verbruikt.

Wat zit er feitelijk in een opgevangen bericht?

Meer dan alleen de body, en in de extra onderdelen leven de nuttige asserties. Een opgevangen bericht draagt de envelopinformatie van de overdracht samen met het bericht zelf, wat betekent dat een test kan controleren van wie het bericht beweert te zijn, naar welk adres het is verzonden, de onderwerpregel, het inhoudstype en de body in de vorm waarin je applicatie die heeft geproduceerd.

Dat is belangrijk omdat de bezorging niet het ding is dat wordt getest. De inhoud is dat. Een suite die alleen verifieert dat een bericht is geaccepteerd, slaagt vrolijk terwijl de template een lege naam weergeeft of de link naar de verkeerde omgeving wijst.

Moet een falende test het ruwe bericht bewaren?

Ja, en het moet dat bewust doen in plaats van per ongeluk. Wanneer een assertie over de body faalt, is het nuttigste artefact het bericht zoals het daadwerkelijk is geproduceerd. Zonder dat is de volgende stap meestal de storing met de hand lokaal reproduceren, en dat is precies het handmatige werk dat het opvangpunt moest wegnemen.

Twee gewoonten maken het artefact nuttig. Voeg het toe aan de falende run in plaats van aan een gedeelde locatie, zodat gelijktijdige runs elkaar niet kunnen overschrijven. En behandel het als testdata wanneer het wordt opgeslagen: een opgevangen bericht kan adressen en gegenereerde waarden uit de run bevatten, en het zou volgens hetzelfde korte schema moeten worden bewaard als de rest van de uitvoer van de run. Adressen die zo worden gebruikt, bestaan voor asserties, nooit als echte identiteiten.

Wanneer je in plaats daarvan een echt postvak nodig hebt

Een lokale opvang kan geen vragen beantwoorden die met de buitenwereld te maken hebben. Als de test moet bewijzen dat een bericht een echt bezorgpad overleeft, of dat het systeem van een derde erop reageert, dan moet er iets de machine verlaten.

Voor die gevallen is een wegwerppostvak vaak genoeg: een adres dat voor de run is aangemaakt, één keer gelezen, weggegooid. De tijdelijke mailpagina maakt er een op verzoek aan, en omdat niemand het heeft geregistreerd, begint het postvak leeg en bevat het niets anders dan het verkeer dat de test heeft geactiveerd. Het onderscheid is de moeite waard om scherp te houden in je hoofd: lokale opvang is voor asserties over wat je applicatie verzendt, en een echt postvak is voor asserties over wat aankomt.

Voor ontwikkelaars: poorten, parallellisme en asserties

Vier beslissingen bepalen of deze regeling saai blijft.

Het opvangpunt alleen aan de loopbackinterface binden is de eerste. Het beperkt de blootstelling en maakt duidelijk dat het eindpunt geen maildienst is voor iets buiten de run. Laat de poort uit de omgeving komen in plaats van uit een constante, zodat twee runs op één machine niet kunnen botsen.

Runs isoleren is de tweede. Geef elke run zijn eigen eindpuntproces, of op zijn minst zijn eigen opslag, en geef elk geval zijn eigen ontvangeradres. Een gedeelde wachtrij die door meerdere tests parallel wordt gelezen, levert de meest irritante klasse van storing op die er bestaat: een test die alleen slaagt en in een volledige pipeline faalt.

Op inhoud asserten in plaats van op verstreken tijd is de derde. Omdat de overdracht synchroon is, valt er niets te wachten; een sleep in dit soort test is een teken dat er iets via de verkeerde interface wordt getest.

Luidruchtig falen is de vierde. Wanneer een assertie over een bericht faalt, print of voeg dan het deel toe dat is vergeleken. Een test die alleen een mismatch meldt, zonder het bericht te tonen dat hij heeft gelezen, stuurt de volgende persoon terug naar handmatige reproductie.

Als je opvangpad tests voedt die korte codes lezen in plaats van bodies, behandelt OTP testen in end-to-end suites de kant van het parsen, en behandelt de aanpak met een vangnet-mailbox wat je moet doen wanneer een omgeving echt een heel domein nodig heeft in plaats van één eindpunt.

Volgende stappen

Zoek de ene test in je suite die mail via een provider verzendt, en tel hoe vaak die is gefaald om redenen die niets te maken hebben met de wijziging die wordt getest. Geef hem dan voor één run een lokaal eindpunt en vergelijk. Houd de publieke provider voor alles wat het open internet echt nodig heeft; de rest hoort op de machine die de tests draait.

Verder lezen

Handleidingen over Tijdelijke e-mail (wegwerp-e-mail / e-mail van 10 minuten)