Een willekeurige adresgenerator lijkt het eenvoudigste hulpmiddel in een testgereedschapskist en gedraagt zich als een van de subtielste. Willekeur is juist nuttig omdat het combinaties verkent die niemand heeft opgeschreven, maar een adres is geen zak met onafhankelijke waarden — het is een klein web van relaties, en willekeur die afzonderlijk op elk veld wordt toegepast, vernietigt die relaties.
Deze gids legt uit wat willekeurig moet zijn en wat dat nooit mag zijn, waarom een reproduceerbare sleutel meer uitmaakt dan een grote pool van varianten, hoe batchexport de vorm van je testsuite verandert, en welke fouten met meerdere landen steeds weer opduiken. Aan het einde weet je hoe je variatie krijgt zonder tegenstrijdigheden.
Waarom zijn willekeurig en inconsistent verschillende problemen?
Een willekeurig adres is niet hetzelfde als een willekeurig gekozen adres. De willekeur leeft in de delen die geen relaties dragen: het huisnummer, de gebouwnaam, de exacte spellingvariant van een straat, de volgorde van records in een batch. De deterministische delen zijn de delen die elkaar beperken, en die moeten worden afgeleid in plaats van getrokken.
Sta stil bij wat er gebeurt wanneer elk veld onafhankelijk wordt getrokken. De stad wordt uit de ene lijst getrokken, de administratieve onderverdeling uit een andere, de postcode uit een derde, en het netnummer uit een vierde. Elke individuele waarde is geldig, en de combinatie is dat niet. Vier geldige waarden produceren een ongeldig record, en geen enkele zorg bij het selecteren van elke lijst voorkomt dat.
De regel die dit oplost, is de generatievolgorde. Kies het land, dan de eerstelijns onderverdeling, dan de plaats, en leid daarna de postcode en het telefoonvoorvoegsel uit die keten af. Willekeur wordt dan alleen toegepast waar die niets kan tegenspreken, wat je variatie geeft zonder de klasse van fouten waaraan handmatig gebouwde fixtures lijden. Het artikel over de Amerikaanse adresgenerator toont hetzelfde principe toegepast binnen één land.
Er is een nuttige manier om het verschil te beschrijven. Een willekeurige adresgenerator trekt geen twaalf velden; hij trekt een locatie en beschrijft die vervolgens in het formaat dat die locatie gebruikt. Zodra je het record eerst als een plaats en pas daarna als een set velden beschouwt, houdt de afleidingsvolgorde op een technisch detail te zijn en wordt het de voor de hand liggende manier om het ding te bouwen.
Wat moet willekeurig zijn en wat moet vastliggen?
De waarden die moeten variëren, zijn de waarden die een formulier als ondoorzichtige invoer consumeert: straatnamen binnen een geldige verzameling, huisnummers, unit-aanduidingen, bedrijfsnamen, namen van ontvangers, en de ordening van records in een export. Het variëren hiervan beoefent de lay-out, de lengtelimieten en de tekenbehandeling van je velden, en dat is precies waarvoor een willekeurige generator dient.
De waarden die moeten vastliggen, zijn de waarden waaraan relaties hangen. De onderverdeling moet bij de plaats passen. De postcode moet bij de onderverdeling passen. Het telefoonvoorvoegsel moet bij de regio passen. Het land moet bij het formaat van elk ander veld passen. Geen van deze mag onafhankelijk worden getrokken, en een hulpmiddel dat voor een van hen een “volledig willekeurige” modus biedt, biedt je een fout aan.
Er is een derde categorie die het benoemen waard is: waarden die in sommige tests willekeurig moeten zijn en in andere bevroren. Een geboortedatum is bijvoorbeeld nuttig willekeurig wanneer je jaargrensfouten jaagt en schadelijk wanneer je op een specifiek antwoord toetst. De beslissing hoort bij de test, niet bij de generator, en daarom is een generator die je afzonderlijke velden laat vastzetten nuttiger dan een die slechts één willekeurige modus biedt.
Waarom reproduceerbaarheid wint van variatie
Dezelfde sleutel en hetzelfde land horen altijd hetzelfde record te produceren. Dit klinkt als een beperking van de willekeur en is in feite de eigenschap die gegenereerde data überhaupt bruikbaar maakt in geautomatiseerd testen.
Een bewering vergelijkt een waargenomen waarde met een verwachte. Als de invoer tussen runs verandert, moet de verwachte waarde mee veranderen, en de test houdt op iets over gedrag te beweren en begint te beweren dat de generator onvoorspelbaar is. Dat is een test die alleen om de verkeerde redenen kan falen.
Reproduceerbaarheid maakt fouten ook reproduceerbaar. Wanneer een test faalt op een gegenereerd record, is de eerste vraag wat het record bevatte. Met een sleutel kun je het exact opnieuw genereren en inspecteren. Zonder een sleutel is het record verdwenen, is de fout onherhaalbaar, en wordt het bugrapport een anekdote.
Dit is de eigenschap waar de adresgenerator op deze site omheen is gebouwd: één sleutel, één land, één stabiel record, en een andere sleutel telkens wanneer je een ander wilt. Het is ook de reden waarom een generator die alleen een shuffelknop biedt een zwakker hulpmiddel is dan het in eerste instantie lijkt, want een shuffle kan niet worden herhaald wanneer een build volgende maand faalt en niemand de data die de fout veroorzaakte kan reproduceren.
Het praktische patroon is om één stabiele sleutel per fixture te gebruiken. Eén sleutel voor de fixture die het gelukkige pad aandrijft, een andere voor het record met een ongewoon lange straatnaam, weer een andere voor het record waarvan de postcode het uitgebreide achtervoegsel draagt. Een sleutel per fixture is beter dan een sleutel per test, omdat verscheidene tests hetzelfde record kunnen delen en een wijziging eraan een bewuste handeling wordt in plaats van een ongeluk. Het artikel over adresdata in testfixtures beschrijft hoe je die sleutels organiseert zodat een testsuite leesbaar blijft terwijl hij groeit.
Hoe verandert batchexport je testsuite?
Een enkel gegenereerd adres ondersteunt een handmatige controle. Een batch van tienduizend ondersteunt een heel ander soort testen, en het exportformaat doet er meer toe dan het aantal. Een CSV met één rij per adres en stabiele kolomkoppen laat je een datagestuurde testlus aansturen, een stagingdatabase seeden, en aantallen en verdelingen na een migratie vergelijken.
Twee eigenschappen maken een export bruikbaar. De eerste is dat de kopregel de velden benoemt zoals je schema ze benoemt, zodat de mapping expliciet is in plaats van geraden. De tweede is dat elke rij een markering draagt die hem als gegenereerde data identificeert, hetzij in een speciale kolom, hetzij in de bestandsnaam en de datasetnotities, zodat een verdwaalde export niet voor een productie-extract kan worden aangezien.
Grote batches brengen ook problemen aan het licht die kleine verbergen. Als je duizend adressen voor één land exporteert en de postcodes clusteren in een handvol waarden, of de stedenlijst herhaalt zich na twintig rijen, dan onthult de batch een dekkingsprobleem dat een steekproef van tien records nooit zou tonen. Verdelingsfouten zijn het soort fout dat alleen bij volume verschijnt, wat nog een reden is om met volume te testen.
Wat breekt het eerst wanneer je landen mengt?
Generatie over meerdere landen is waar de meeste interessante fouten leven, omdat de relaties die binnen één land gelden niet over de grenzen bestaan. De eerste fout is de mismatch tussen postcode en regio, waarbij een geldige postcode uit het verkeerde land aan een geldige stad wordt gekoppeld, wat geen enkele validator voor één veld ooit zal opvangen.
De tweede is het telefoonvoorvoegsel. Een nummer dat het belvoorvoegsel van het ene land draagt terwijl het adres in een ander ligt, is een mismatch die een zorgvuldige testsuite zou moeten markeren, en de relatie tussen voorvoegsel en plaats is gedocumenteerd in het artikel over telefoonvoorvoegsel en plaatsmatching. De derde is het veldensetprobleem: landen delen geen schema, dus een record dat voor een land zonder postcode is gegenereerd, produceert een leeg veld waar je test vijf cijfers verwachtte.
De vierde fout is subtieler en komt uit het formulier in plaats van uit de data. Als je adressjabloon voor elk land op een staatveld staat, dan zal elk gegenereerd record een staatswaarde dragen die in de meeste ervan niets betekent. Het artikel over het internationale adresformaat legt uit hoe veldensets per land verschillen en waarom een universeel sjabloon een compromis is in plaats van een oplossing.
Er is een vijfde fout die alleen verschijnt wanneer records met elkaar worden vergeleken. Een batch die landen mengt, sorteert niet correct onder één collatie, omdat de letters van de ene taal anders ordenen dan de letters van een andere. Een lijst die door elkaar gegooid lijkt, is meestal helemaal niet door elkaar gegooid; hij is met de verkeerde regels gesorteerd, en de oplossing hoort in de weergavelaag in plaats van in de data.
Zijn willekeurige adressen nuttig voor belastingstests?
Ja, met één voorwaarde: de belastingsgenerator mag niet meer tijd besteden aan genereren dan het systeem aan bedienen. Een generator die een goed gevormd record in constante tijd produceert, is geschikt voor belastingsoefeningen, en een die elk record tegen een externe dienst valideert niet.
Het nuttige patroon is om een grote batch offline te genereren, die op te slaan, en de belastingstest uit die batch te laten lezen in plaats van de generator in de hete lus aan te roepen. Dit maakt de belastingstest ook reproduceerbaar, omdat dezelfde batch bij elke run opnieuw wordt afgespeeld en de enige overgebleven variabele het geteste systeem is.
Fuzzing is het omgekeerde geval. Daar wil je opzettelijk misvormde invoer, en een generator die alleen geldige records produceert, helpt niet. De productieve aanpak is om een geldig record te genereren en het dan op gecontroleerde manieren te muteren — een veld afkappen, een teken buiten de verwachte verzameling invoegen, de postcode vervangen door een waarde uit een ander land — en vast te leggen welke mutatie het systeem tolereerde. Een mutatie die door een formaatcontrole komt maar een stroomafwaarts proces breekt, is een bevinding die het waard is om te hebben. Houd de mutatiecatalogus onder versiebeheer naast de generatorinstellingen, zodat een mutatie die ooit een fout veroorzaakte, daarna bij elke run opnieuw wordt afgespeeld.
Wat een willekeurig record niet kan zijn
Een gegenereerd adres is synthetische data met een correcte structuur en intern consistente velden. Het is geen bezorgbare locatie, het komt overeen met geen enkel gebouw, en het staat op naam van geen enkele persoon of organisatie. Het zal door geen enkele vervoerder worden geaccepteerd en het kan niet dienen als bewijs van woonplaats.
Die grens is het waard om in de dataset zelf te vermelden, niet alleen in een document ernaast. Een kolom die de rijen als gegenereerd markeert, een bestandsnaam die dat zegt, en een notitie in de fixture die beschrijft waarvoor de data dient, maken een ongeluk samen veel minder waarschijnlijk, en een ongeluk is hoe testdata ergens terechtkomt waar het nooit bedoeld was.
Willekeur maakt data ook niet anoniem als de waarden van echte mensen zijn gehaald. Een echte naam en een echt adres uit een echt record halen en ze door elkaar gooien, levert een ander soort probleem op in plaats van een opgelost probleem. Het enige veilige testrecord is een record dat nooit van iemand is geweest.
Er is nog één eigenschap die het benoemen waard is, omdat die makkelijk verloren gaat wanneer een hulpmiddel wordt beoordeeld op de variatie van zijn uitvoer. Een willekeurig record is nog steeds een record, en een record met een doel hoort op te slaan te zijn. Als je het gegenereerde adres niet in een bestand kunt schrijven, als fixture kunt vastleggen, en zes maanden later uit een notitie opnieuw kunt genereren, dan kost de willekeur je reproduceerbaarheid zonder je iets te kopen wat je niet uit een grotere vaste steekproef had kunnen halen.
Elk record dat op deze manier wordt geproduceerd, bestaat om software te testen, en niets anders. Het mag niet worden gebruikt om iemand na te doen, om echte accounts te openen of te registreren, om daadwerkelijke post te ontvangen, om een adres of een identiteit aan te tonen, of om een verificatiestap te omzeilen.