Advertentie
Softwareontwikkeling
Screenshot-diffs in de praktijk: baselines, drempelwaarden en valse alarmen
Twee screenshots vergelijken — klinkt triviaal, maar het is een ambacht: hoe baselines ontstaan, waarom pixelvergelijkingen neigen tot valse alarmen, wat drempelwaarden opleveren en waar de grens loopt tussen beeldvergelijking en oordeel.

Op papier is een visuele test de eenvoudigste testsoort ter wereld: twee beelden, een vergelijking, klaar. Wie het uitprobeert, merkt snel dat tussen „twee beelden vergelijken" en „betrouwbaar weten of de website kapot is" een heel ambacht ligt. Dat ambacht heeft drie kernbegrippen — baseline, drempelwaarde, vals alarm — en wie ze begrijpt, begrijpt ook waarom visuele tests in sommige teams onmisbaar zijn en in andere na drie weken weer worden uitgeschakeld.
Aan het begin staat de baseline: een set screenshots die de gewenste toestand van de pagina vasthoudt. Belangrijk is wat de baseline betekent — en wat niet. Ze is geen objectieve maatstaf voor correctheid, maar een momentopname die iemand tot gewenste toestand heeft verklaard. Een diff tegen de baseline zegt daarom nooit „de pagina is kapot", maar alleen „de pagina is anders dan de vrijgegeven stand". Of anders ook slechter betekent, kan geen algoritme beslissen.
De vergelijking zelf werkt in grondbeginsel pixelgewijs: voor elke beeldpositie wordt de kleurafwijking tussen baseline en actuele screenshot bepaald, de som van de afwijkingen levert een maat voor de verandering. Dat grondbeginsel is robuust en snel — en het heeft een ingebouwde zwakte: het behandelt elke afwijking gelijk, of er nu een winkelwagenknop verdwenen is of de anti-aliasing van een lettertype minimaal anders is uitgevallen.
Precies daaruit komt het grootste praktijkprobleem van visuele tests voort: ruis. Anti-aliasing van lettertypen valt per systeem en per renderronde anders uit. Randen worden nu eens een subpixel eerder, dan weer later getekend. Beelden doorlopen compressie die minimale kleurafwijkingen veroorzaakt. Niets daarvan is een regressie — maar alles daarvan produceert pixelverschillen. Een naïeve vergelijking die bij elke afwijkende pixel alarm slaat, meldt daarom vrijwel altijd iets.
De tweede ruisbron is de inhoud zelf. Een ingevoegde kloktijd verandert bij elke oproep. Een carrousel staat nooit twee keer op hetzelfde beeld. Advertentieplekken leveren wisselende motieven, aanbevelingsbalken wisselende producten, een cookiebanner verschijnt nu eens vóór, dan weer na de screenshot. Wie een nieuwssite 's ochtends en 's middags fotografeert, krijgt twee volstrekt verschillende beelden — en beide zijn correct.
Het werktuig tegen de ruis heet drempelwaarde: pas wanneer de afwijking een gedefinieerde maat overschrijdt, geldt de vergelijking als opvallend. Daarmee begint een afweging die zich niet laat wegoptimaliseren. Een strenge drempelwaarde meldt elke kleinigheid en veroorzaakt alarmmoeheid; een royale ziet echte fouten over het hoofd — een verschoven prijsvermelding kan onder de drempel blijven wanneer ze slechts enkele pixels betreft. De ene juiste waarde bestaat niet; er bestaat alleen de passende waarde voor een bepaalde pagina en een bepaald team.
Voor het vastleggen bestaat in elk geval een handvast procedé: de eigen ruis meten. Daartoe fotografeert men dezelfde pagina twee keer onmiddellijk na elkaar, zonder ook maar iets te veranderen, en vergelijkt men de beide opnamen met elkaar. Elk verschil dat die vergelijking meldt, is per definitie ruis — anti-aliasing, compressie, timing. Wie die meting voor de belangrijkste pagina's en apparaatcombinaties herhaalt, kent het grondniveau van de eigen testomgeving en kan de drempelwaarde er net boven leggen in plaats van hem te raden. Het procedé levert er meteen een vroegwaarschuwingssignaal bij: stijgt het zo gemeten grondniveau later merkbaar, dan is de omgeving onrustiger geworden — en loont het de moeite de oorzaak na te gaan voordat de alarmen hun geloofwaardigheid verliezen.
Alarmmoeheid is daarbij geen zacht bijthema, maar de vaakst voorkomende doodsteek voor visuele tests. Een controlesysteem dat drie keer per dag zonder reden aanslaat, zal na twee weken door niemand meer serieus worden genomen — en dan is het alarm dat daadwerkelijk een kapotte betaalpagina meldt, nog maar één van de vele die men routineus wegklikt. Een visuele test die het team niet vertrouwt, is slechter dan helemaal geen, omdat hij een zekerheid voorwendt die hij niet levert.
Daarom loont werk aan de randvoorwaarden voordat er aan de drempelwaarde wordt gedraaid. Beproefd zijn vaste voorbeelddata in plaats van livedata in testomgevingen, uitgeschakelde animaties, consistente uitgangstoestanden — bijvoorbeeld een al beantwoorde cookiedialoog —, voldoende wachttijden tot alles volledig geladen is en identieke venstergroottes voor elke ronde. Werktuigspecifieke aanwijzingen daarover horen in elke invoering thuis; voor de hier besproken dienst bundelt de documentatie van ScanU op de website van de aanbieder ze. Elk van die maatregelen verwijdert een ruisbron — en maakt de drempelwaarde minder belangrijk, omdat echte en valse alarmen zich duidelijker scheiden.
Voor hardnekkige ruisbronnen — de advertentieplek, de livedatum, het gedeelte met gebruikersreacties — bieden sommige werktuigen bovendien de mogelijkheid beeldgebieden van de vergelijking uit te sluiten. Dat is effectief, maar heeft een prijs die men zou moeten kennen: een uitgesloten gebied is een blinde vlek. Precies daar kan voortaan van alles gebeuren zonder dat iemand het meldt. De afweging luidt daarom niet „uitsluiten of valse alarmen verdragen", maar: is dit gebied belangrijk genoeg dat men van veranderingen wil weten? Voor een roterende reclamebanner luidt het antwoord meestal nee, voor een prijskolom altijd ja. Gedefinieerde uitsluitingsgebieden horen bovendien gedocumenteerd en af en toe nagelopen te worden — anders stapelen stille vlekken zich op, en dekt de controle minder af dan alle betrokkenen denken.
Een verwante beslissing betreft de beelduitsnede. Een opname van het zichtbare venstergedeelte toetst wat bezoekers zonder scrollen zien — snel en zuinig, maar blind voor alles daaronder. Een opname over de volle paginalengte legt alles vast, maar reageert gevoeliger: groeit een element in het bovenste deel met twintig pixels, dan verschuift de hele rest van de pagina naar beneden, en markeert de vergelijking vlakken die inhoudelijk helemaal niet veranderd zijn. Voor compacte, stabiele pagina's is de volle lengte meestal de juiste keuze; bij zeer lange, levendige pagina's kan het slimmer zijn gericht de kritieke secties te toetsen. Ook dat is geen technische futiliteit, maar een beslissing over welke fouten men wil zien — en welke men bewust op de koop toe neemt.
Het tweede grote methodiekthema is het onderhoud van de baseline in de loop van de tijd. Websites veranderen met opzet: redesigns, nieuwe inhoud, seizoensacties. Na elke gewenste wijziging moet de baseline worden nagetrokken, anders meldt elke toekomstige ronde datzelfde verwachte verschil. Het gevaar schuilt in de routine: wie baseline-updates als een lastige klik opvat, actualiseert vroeg of laat reflexmatig — en verklaart daarmee vroeg of laat een echte fout tot de nieuwe gewenste toestand. Vanaf dan bevestigt elke groene ronde de kapotte versie.
Daartegen helpt een eenvoudig grondbeginsel: baseline-updates zijn vrijgaven en verdienen dezelfde zorgvuldigheid als een code review. Iemand bekijkt het verschil, iemand beslist bewust, iemand kan de beslissing later navolgen. Werktuigen ondersteunen dat in verschillende mate; ScanU bijvoorbeeld zet baseline en actuele stand naast elkaar en genereert deelbare rapporten, zodat ook niet-technici een afwijking kunnen beoordelen — welke vergelijkingsfuncties er in detail beschikbaar zijn, laat de functiepagina van de dienst zien. Het principe is echter werktuigonafhankelijk: de vrijgave van een baseline is een inhoudelijke beslissing, geen technische.
Eén dimensie wordt in inleidende teksten graag verzwegen: de tijd. Regressies vallen niet altijd meteen op. Dan begint de zoektocht: sinds wanneer is dat zo? Welke wijziging komt in aanmerking? Hier betaalt historie zich uit — de mogelijkheid oudere standen in te zien en het tijdstip van de verandering af te bakenen. Bij ScanU hangt de bewaring van het prijsniveau af, van drie dagen in het gratis niveau tot 90 dagen in het grootste. Voor de methodiek betekent dat: wie slechts zelden controleert, heeft verder terugreikende verlopen nodig; wie dagelijks controleert, bakent perioden ook met een korte historie goed af.
Blijft de meest fundamentele grens van het procedé: de semantische kloof. Een pixelvergelijking weet niet wat ze vergelijkt. Twee pixels verschuiving bij een betaalknop kunnen een symptoom zijn van een kapot lay-outgrid; twintig pixels verschuiving in een voettekst zijn meestal onbeduidend. De diff kent het verschil niet — hij meet oppervlakte, geen betekenis. Het laatste woord heeft daarom altijd een mens die de pagina kent en kan inschatten welke afwijking zakelijke relevantie heeft.
En ten slotte dat wat een screenshot-diff principieel niet kan zien: alles wat zich niet in het beeld neerslaat. Een pagina kan er foutloos uitzien en toch verkeerde gegevens tonen, een formulier kan perfect gerenderd zijn en bij het verzenden falen, een server kan verouderde inhoud correct uitleveren. Visuele tests zijn één laag in het testbouwwerk — naast functionele tests, monitoring en incidentele menselijke nieuwsgierigheid —, niet de vervanging daarvan.
Hoe de afzonderlijke bouwstenen in elkaar grijpen, laat een doorgespeeld voorbeeld zien — geen casestudy, maar een typische opeenvolging. Week één: een team legt voor tien pagina's baselines aan en treft de volgende ochtend tientallen gemelde afwijkingen aan. Het doorlopen ervan laat zien dat bijna alle terug te voeren zijn op een carrousel en de cookiedialoog. Week twee: de testomgeving tot rust brengen — vaste voorbeelddata, gedefinieerde uitgangstoestand, animaties uit; de ronden worden stil. Week drie: een dependency-update verschuift in een van de drie engines de afstanden van de navigatie — de eerste echte vondst, die eerder niemand zou hebben opgemerkt, omdat in de dagelijkse praktijk niemand routinematig alle engines opent. Week vier: een redesign van de homepage veroorzaakt verwachte verschillen op alle weergaven; na beoordeling wordt de baseline bewust bijgewerkt. Niets aan dit verloop is spectaculair — en precies daarin zit het punt. De waarde ontstaat niet door dramatische vondsten, maar door de overgang van „waarschijnlijk ziet alles er goed uit" naar een gecontroleerd „sinds de laatste vrijgegeven stand is er niets ongewenst veranderd". Hoe een enkele controleronde daarbij technisch verloopt, laat de stap-voor-stapweergave van ScanU zien.
Wie wil instappen, vaart wel bij een eenvoudige volgorde: eerst een kleine set belangrijke pagina's definiëren, dan de testomgeving tot rust brengen, dan baselines aanmaken en in het team afstemmen wie afwijkingen beoordeelt en vrijgeeft — en pas daarna over drempelwaarden en controlefrequentie onderhandelen. Een Nederlandstalige introductie op het onderwerp biedt het overzicht van ScanU in het Nederlands; de methodiek erachter geldt voor elk werktuig van dit slag. Want dat is uiteindelijk het centrale inzicht: de waarde van visuele tests ontstaat niet in het algoritme dat pixels vergelijkt, maar in het procedé eromheen — zuivere referenties, eerlijke drempels en mensen die verschillen beoordelen in plaats van ze weg te klikken.