Automatiser manuell testing: - Fant noe som passa perfekt

Audun i Busy om hvordan de kjører visuell testing med TestCafé og Percy.

Audun Wigum Arbo skriver i blogginnlegget om hvordan de automatiserer visuell testing. 📸: Privat
Audun Wigum Arbo skriver i blogginnlegget om hvordan de automatiserer visuell testing. 📸: Privat Vis mer

Hos Busy – som i et hvert annet softwareselskap – er testing en sentral del av hverdagen. Som produktutviklere skriver vi kode som igjen blir til et produkt. Hvordan vet vi at koden vi skriver i virkeligheten resulterer i produktet vi så for oss? Jo, vi tester.

Alle som driver med utvikling må innom testing på et eller annen tidspunkt. Det første jeg tenkte på da jeg hørte tester var enhetstester, integrasjonstester, ende-til-ende-tester og andre former for automatisk testing. Som utvikler glemmer jeg ofte – eller kanskje bare tar for gitt – den mest vanlige og samtidig mest tidkrevende testingen; nemlig manuell testing.

Før vi pusher ut nye versjoner av produkter, tester vi gjerne manuelt. Vi går gjennom det som er endret, og sjekker at relaterte ting ser visuelt riktig ut og fungerer funksjonelt sett som vi forventet.

Her kommer det åpenbare spørsmålet: kan vi som utviklere automatisere bort dette? Ja, sier vi i Busy.

Visuelle tester

Høsten 2020 satt vi oss ned for å finne ut av én ting: hvordan automatisere bort så mye manuell testing som mulig, og samtidig føle oss like sikre, eller kanskje enda mer sikre, på at det vi pusher ut er av høy kvalitet og ikke ødelegger ting som fungerte fint tidligere?

Etter diskusjon og undersøkelse av verktøy, fant vi noe som passet perfekt: Visuell testing. Gjennom et eksempel fra vårt eget produkt, skal jeg vise hva visuell testing innebærer, og hvorfor akkurat det ble løsningen på vårt problem.

NB: Visuell testing kan brukes i mange sammenhenger, men vi viser her spesifikt hvordan det kan brukes til å teste en hel applikasjon.

TestCafé og Percy

Når man skal utføre visuell testing for en hel applikasjon, trenger man to grunnleggende komponenter:

  1. Et testrammeverk for å navigere oss rundt og utføre handlinger i webappen. Vi bruker TestCafé, et rammeverk for ende-til-ende-testing i nettlesere. Mange kjenner allerede til Cypress, som er et lignende produkt som også kan brukes med visuell testing. Man får mye for pengene med en gang man begynner å skrive ende-til-ende-tester for webapper, da man relativt enkelt kan kjøre opp et produksjonslignende miljø der man kan teste hele applikasjonen (i vårt tilfelle database, backend og frontend) der testkoden utfører handlinger i en ekte nettleser.
  2. Et verktøy for å ta og senere sammenligne bilder fra tester. Vi bruker Percy, som er en software as a service (SaaS) som virkelig gjør visuell testing spennende og enkelt. Percy tilbyr et produkt der man laster opp snapshots fra tester, og deretter får mulighet til gå gjennom visuelle endringer. De tilbyr også integrasjon med blant annet GitHub, der man enkelt kan sette opp så en gjennomgang av visuelle endringer blir et påkrevd steg for å godkjenne en pull request.

Et (visuelt) eksempel med kode

Samspillet mellom verktøyene kan forklares relativt enkelt. Siden dette er et småteknisk innlegg, tar jeg like gjerne forklaringen i et eksempel! 😄

Et av målene med Busy som et produkt er å gjøre det så lett som mulig å både føre tid, planlegge tid og føre kostnader for den enkelte ansatte i et selskap. Vi må være sikre på at det mest kritiske i vår applikasjon fungerer som det skal, uansett hvor vi gjør endringer i kodebasen. Føring av kostnader er derfor et perfekt eksempel på noe vi vil ha visuelle- og ende-til-ende-tester for.

Her tar vi for oss testing av scenarioet der en bruker vil føre en ny kostnad.

Steg #1: Å komme seg til der man vil ta bilder

Vi starter med å skrive en ny ende-til-ende-test i TestCafé. Hensikten med denne, fra en visuell tests perspektiv, er å komme seg fram til stedene man vil ta et bilde. En kostnad opprettes ved å trykke på en «Opprett ny kostnad»-knapp, som åpner en popup der man blant annet velger prosjekt, produkt og en valgfri kommentar.

Popup for å opprette en kostnad.
Popup for å opprette en kostnad. Vis mer

Vi skriver derfor en TestCafé-test som åpner popupen, legger inn noe info, og trykker lagre. Vi bruker React, men man kan fint bruke vanlige CSS-selectors for å finne elementer på siden.

test.page("/costs")("Creates a cost", async (t) => {
   // Vi finner «Opprett ny kostnad»-knappen, og trykker på den
   const createButton = ReactSelector("Button").withKey("new_cost_button");
   await t.expect(createButton.exists).ok();
   await t.click(createButton);

   // Vi finner alle inputfelter, samt lagre-knappen for opprettelsesvinduet
   const saveCostButton = ReactSelector("LoadableButton").withProps({
       type: "submit",
   });
   const commentField = ReactSelector("InputField").withKey("comment_input");
   const projectSelect = ReactSelector("ProjectSelect").withKey(
       "project_input"
   );
   const projectToSelect = Selector("#inner_option_0_0");
   const productSelect = ReactSelector("ProductSelect").withKey(
       "product_input"
   );
   const firstProductOption = ReactSelector("Option").withProps({
       value: MockProduct.APPLE_IPHONE_DISPLAY.id,
   });

   // Vi skriver inn en kommentar på kostnaden, velger prosjekt og produkt, og trykker lagre
   await t
       .expect(saveCostButton.exists)
       .ok()
       .typeText(commentField, "Made some cheap repairs")
       .click(projectSelect)
       .click(projectToSelect)
       .click(productSelect)
       .click(firstProductOption);

   await t.click(saveCostButton);
});

Om vi kjører denne testen, vil TestCafé åpne en nettleser og utføre våre handlinger. Videoen nedenfor viser ikke et menneskes handlinger – den utføres automatisk av TestCafé!

Popup for å opprette en kostnad.

Steg #2: Ta bilder! 📸

Vi har nå en test som greier å navigere rundt og utføre de handlingene vi vil. Da er det bare å bestemme seg for hvor vi vil ha visuell testing av scenarioet – eller med andre ord, hvor vi vil ta bilder.

Ved å kalle funksjonen percySnapshot , tar man enkelt et bilde som sendes til Percys webapp (bildet er i virkeligheten et DOM-snapshot som rendres på nytt hos de). La oss gjøre dette i testen vår:

test.page("/costs")("Creates a cost", async (t) => {
   // Vi finner "Opprett ny kostnad"-knappen, og trykker på den
   const createButton = ReactSelector("Button").withKey("new_cost_button");
   await t.expect(createButton.exists).ok();

   // Vi tar et bilde av den tomme kostnadslisten
   await percySnapshot(t, "Cost list placeholder");
   await t.click(createButton);

   // Vi finner alle inputfelter, samt lagre-knappen for opprettelsesvinduet
   const saveCostButton = ReactSelector("LoadableButton").withProps({
       type: "submit",
   });
   const commentField = ReactSelector("InputField").withKey("comment_input");
   const projectSelect = ReactSelector("ProjectSelect").withKey(
       "project_input"
   );
   const projectToSelect = Selector("#inner_option_0_0");
   const productSelect = ReactSelector("ProductSelect").withKey(
       "product_input"
   );
   const firstProductOption = ReactSelector("Option").withProps({
       value: MockProduct.APPLE_IPHONE_DISPLAY.id,
   });

   // Vi skriver inn en kommentar på kostnaden, velger prosjekt og produkt
   await t
       .expect(saveCostButton.exists)
       .ok()
       .typeText(commentField, "Made some cheap repairs")
       .click(projectSelect)
       .click(projectToSelect)
       .click(productSelect)
       .click(firstProductOption);

   // Vi tar et bilde av popupen etter vi har fylt inn informasjon
   await percySnapshot(t, "Create cost modal");

   // Vi trykker på lagre-knappen
   await t.click(saveCostButton);

   // Til slutt tar vi et bilde av kostnadslisten etter opprettelse
   await percySnapshot(t, "Cost list with newly created cost");
});

Steg #3: Gjennomgang av forskjeller! 🔍

Når testen er ferdig kjørt, vil man få en rapport i webappen til Percy. I testskriptet vil man få en direktelink, og om man bruker GitHub-integrasjonen vil man få det der etter kjøring i CI-verktøyet.

image: Automatiser manuell testing: - Fant noe som passa perfekt

Oi! Her har Percy funnet at noe har endret seg mellom et bilde som ble tatt da vi nettopp kjørte testen, og det samme bildet, bare tatt i vår master-branch. Går vi inn på til Percy, får vi et eget verktøy for å gå gjennom disse forskjellene:

image: Automatiser manuell testing: - Fant noe som passa perfekt

Her ser vi at ett av bildene vi tar i testen nå har forandret seg; bildet med beskrivelse "Create cost modal". Percy viser oss nøyaktig hva som er annerledes ved å markere dette i rødt. Vil man heller se før-og-etter-bilder kan man også det:

Før- og etter-bilde.

I den nye pull requesten ser det visst ut som utvikleren har tullet litt med CSS-en. I dette tilfellet er det ganske tydelig at noe er galt, men i mange tilfeller vil ikke manuell testing greie å avdekke slike endringer.

Verdien vi får av visuell testing

Å automatisk kunne sjekke funksjonalitet, både programmatisk og visuelt har vært revolusjonerende for oss. Vi kan nå få med oss når vi med uhell brekker ting som vi ikke trodde var relatert til endringene vi gjorde.

Vi kan derfor komfortabelt pushe ut nye endringer i raskt tempo, uten å bekymre oss over at GUI plutselig endrer seg på rare måter, eller at kjernefunksjonalitet har brekt.

Oppsummert er det mange gode grunner til å implemtere:

  • Når man har fått satt opp testrammeverket er testene veldig enkle å både forstå og skrive, da de hovedsakelig beskriver hva et menneske ville gjort i nettleseren.
  • Man kan få utrolig god testdekning av de tilfellene man bryr seg om i applikasjonen, både funksjonelt og visuelt.
  • Man sparer tid på manuell testing. Ved å ha en god samling med tester kan man fokusere på det en kodeendring skulle endre, i stedet for å bekymre seg om alt annet.
  • Spar tid på fiksing av bugs. Dette gjelder nok alle former for automatisk testing, men jo tidligere du avdekker en bug, jo raskere er den å fikse! Om en sluttbruker finner bugen startes en lang prosess. Man får gjerne en supportmelding, og så må man jobbe med å reprodusere bugen. Man må så bytte kontekst fra det man egentlig holdt på med for å fikse den, og til slutt få fiksen gjennomgått og pushet ut til produksjon. Om den derimot avdekkes i pull requesten den oppsto, fikser man den bare der og da, og man er ferdig med saken.
  • Man kan verifisere at ting er riktig i flere nettlesere og skjermstørrelser. Percy støtter å rendre et enkelt snapshot flere ganger med forskjellig oppsett: man kan velge både nettleser og skjermstørrelse. Man kan ha så mange konfigurasjoner man vil, men testene kjøres like fort da det kun sendes ett bilde fra testen til Percy. Percy fikser altså resten!

Mer om visuell testing

Denne artikkelen viser bare overflaten av visuell- og ende-til-ende-testing. Det finnes flere tilbydere enn Percy, og det finnes rammeverk som lar deg self-hoste alt.

Om man er interessert i visuell testing av mindre komponenter så har skaperne av Storybook laget Chromatic, et verktøy for visuell testing av komponenter i React- og andre populære rammeverk. Det er heller ikke nødvendig å bruke akkurat TestCafé – det finnes mange andre verktøy, blant et annet som kommer med Percy-biblioteket.

Vi har også lagt ut videoen over der vi diskuterer og viser frem mer av visuell testing innad i Busy.