Testing av dataintensiv kode med Go, del 4

Oversikt

Dette er del fire av fem i en opplæringsserie om testing av datakrevende kode med Go. I del tre dekket jeg testing mot et lokalt komplekst datalag som inkluderer en relasjonell DB og en Redis-cache.

I denne opplæringen går jeg over testing mot eksterne datalager ved hjelp av delte testdatabaser, ved hjelp av øyeblikksbilder av produksjonsdata, og genererer dine egne testdata.

Testing mot eksterne datalager

Så langt ble alle våre tester gjennomført lokalt. Noen ganger er det ikke nok. Du må kanskje teste mot data som er vanskelig å generere eller oppnå lokalt. Testdataene kan være svært store eller endres ofte (for eksempel produksjonsdata snapshot).

I disse tilfellene kan det være for sakte og dyrt for hver utvikler å kopiere de nyeste testdataene til maskinen. Noen ganger er testdataene sensitive, og spesielt fjerntliggende utviklere burde ikke ha den på sin bærbare datamaskin.

Det er flere alternativer her å vurdere. Du kan bruke en eller flere av disse alternativene i forskjellige situasjoner.

Felles testdatabase

Dette er et veldig vanlig alternativ. Det er en delt testdatabase som alle utviklere kan koble til og teste mot. Denne delte test-DB administreres som en delt ressurs, og blir ofte fylt ut periodisk med noen grunnlinjedata, og utviklere kan deretter kjøre tester mot det som søker eksisterende data. De kan også opprette, oppdatere og slette sine egne testdata.

I dette tilfellet trenger du mye disiplin og en god prosess på plass. Hvis to utviklere kjører samme test samtidig som de oppretter og sletter de samme objektene, vil begge tester mislykkes. Vær oppmerksom på at selv om du er den eneste utvikleren og en av testene dine ikke rydder opp etter seg selv, kan den neste testen mislykkes fordi DB nå har noen ekstra data fra den forrige testen som kan ødelegge din nåværende test. 

Kjører testene eksternt

Slik fungerer CI / CD-rørledninger eller til og med bare automatiserte byggesystemer. En utvikler forplikter seg, og en automatisert bygge- og teststart går. Men du kan også bare koble til en ekstern maskin som har koden din og kjøre testene dine der.

Fordelen er at du kan gjenskape det nøyaktige lokale oppsettet, men har tilgang til data som allerede er tilgjengelig i det eksterne miljøet. Ulempen er at du ikke kan bruke favorittverktøyene dine for feilsøking.

Ad-Hoc Remote Test Instance

Lansering av en ekstern ad hoc-testeksempel sikrer at du fremdeles er isolert fra andre utviklere. Det er ganske likt konseptuelt å kjøre en lokal forekomst. Du må fortsatt lansere datalageret ditt (eller butikkene). Du må fortsatt fylle dem (eksternt). Testkoden din kjører imidlertid lokalt, og du kan feilsøke og feilsøke ved hjelp av din favoritt IDE (Gogland i mitt tilfelle). Det kan være vanskelig å administrere operativt hvis utviklere fortsetter å teste forekomster som kjører etter at testene er ferdige.

Bruke stillbilder for produksjonsdata

Når du bruker en delt testdatabutikk, blir den ofte fylt med produksjonsdata snapshots. Avhengig av hvor sensitiv og kritisk dataene er, kan noen av følgende fordeler og ulemper være relevante.

Fordeler og ulemper med å bruke produksjonsdata for testing

Pros:

  • Du tester mot ekte data. Hvis det virker, er du bra.
  • Du kan laste og ytelsestestdata som representerer en faktisk belastning.
  • Du trenger ikke å skrive datageneratorer som prøver å simulere ekte produksjonsdata.

Ulemper:

  • Det kan ikke være lett å teste feilforhold.
  • Produksjonsdata kan være følsomme og krever spesiell behandling.
  • Du må skrive noen kode eller manuelt synkronisere stillbildet ditt med jevne mellomrom.
  • Du må håndtere format eller skjemaendringer.
  • Det kan være vanskelig å isolere problemer som oppstår med rotete produksjonsdata.

Anonymiseringsproduksjonsdata

OK. Du har gjort spranget og besluttet å bruke et produksjonsdata øyeblikksbilde. Hvis dataene involverer mennesker i enhver form eller form, må du kanskje anonymisere dataene. Dette er overraskende vanskelig.

Du kan ikke bare erstatte alle navn og bli ferdig med det. Det er mange måter å gjenopprette PII (personlig identifiserbar informasjon) og PHI (beskyttet helseinformasjon) fra dårlig anonymiserte data øyeblikksbilder. Sjekk ut Wikipedia som utgangspunkt hvis du er nysgjerrig.

Jeg jobber for Helix hvor vi utvikler en personlig genomisk plattform som omhandler de mest private data-den sekvenserte DNA fra mennesker. Vi har noen seriøse beskyttelser mot utilsiktede (og skadelige) data brudd.

Oppdatere tester og data øyeblikksbilder

Når du bruker stillbilder for produksjonsdata, må du periodisk oppdatere øyeblikksbilder og tilsvarende tester. Tidspunktet er opp til deg, men definitivt gjør det når det er et skjema eller formatendring. 

Ideelt sett bør testene dine ikke teste for egenskapene til et bestemt øyeblikksbilde. Hvis du for eksempel oppdaterer stillbildene dine daglig, og du har en test som bekrefter antall poster i øyeblikksbildet, må du oppdatere denne testen hver dag. Det er mye bedre å skrive tester på en mer generisk måte, så du må bare oppdatere dem når koden under test endres. 

Generering av testdata

En annen tilnærming er å generere dine egne testdata. Fordeler og ulemper er de nøyaktige motsetningene til å bruke produksjonsdata snapshots. Legg merke til at du også kan kombinere de to tilnærmingene og kjøre noen tester på produksjonsdata øyeblikksbilder og andre tester ved hjelp av genererte data.

Tilfeldig testdata Generering

Hvordan ville du gå om å generere testdataene dine? Du kan gå vill og bruke helt tilfeldige data. For eksempel kan vi for Songify bare generere helt tilfeldige strenger for brukerens e-post, URL, beskrivelse og etiketter. Resultatet blir kaotisk, men gyldige data siden Songify gjør ingen data validering.

Her er en enkel funksjon for å generere tilfeldige strenger:

func makeRandomString (lengde int) streng const bytes = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" randBytes: = lag ([] byte, lengde) for i: = 0; Jeg < length; i++  b := bytes[rand.Intn(len(bytes))] randBytes[i] = b  return string(randBytes) 

La oss skrive en funksjon som legger til fem tilfeldige brukere og legger til 100 tilfeldige sanger fordelt tilfeldig mellom de fem brukerne. Vi må generere brukere fordi sanger ikke lever i vakuum. Hver sang er alltid knyttet til minst en bruker.

func (m * InMemoryDataLayer) PopulateWithRandomData () users: = [] Bruker  // Opprett 5 brukere for i: = 0; Jeg < 5; i++  name := makeRandomString(15) u := User Email: name + "@" + makeRandomString(12) + ".com", Name: makeRandomString(17),  m.CreateUser(u) users = append(users, u)  // Create 100 songs and associate randomly with // one of the 5 users for i := 0; i < 100; i++  user := users[rand.Intn(len(users))] song := Song Url: fmt.Sprintf("http://www.%s.com", makeRandomString(13)), Name: makeRandomString(16),  m.AddSong(user, song, []Label)   

Nå kan vi skrive noen tester som driver mye data. For eksempel, her er en test som bekrefter at vi kan få alle 100 sanger i en samtale. Merk at testen ringer PopulateWithRandomData () før du ringer. 

func TestGetSongs (t * testing.T) dl, err: = NewInMemoryDataLayer () hvis err! = null t.Error ("Kunne ikke lage lagringsdata i minnet") dl.PopulateWithRandomData () sanger, feil: = dl.GetSongs () hvis err! = null t.Error ("Kunne ikke opprette data i minnet") hvis len (sanger)! = 100 t.Error ('GetSongs () returnerte ikke riktig antall sanger ') 

Regelbasert Test Data Generation

Vanligvis er helt tilfeldige data ikke akseptable. Hver datalager har begrensninger du må respektere og komplekse forhold som må følges for å skape gyldige data som systemet kan operere på. Du kan også generere noen ugyldige data for å teste hvordan systemet håndterer det, men det vil være spesifikke feil du vil injisere.

Tilnærmingen vil være lik den tilfeldige datagenerasjonen, bortsett fra at du vil ha mer logikk for å håndheve reglene. 

For eksempel, la oss si at vi vil håndheve regelen om at en bruker kan ha maksimalt 30 sanger. I stedet for å tilfeldig opprette 100 sanger og tildele dem til brukere, kan vi bestemme at hver bruker vil ha nøyaktig 20 sanger, eller kanskje lage en bruker uten sanger og fire andre brukere med 25 sanger hver. 

Narrative-basert Test Data Generation

I noen tilfeller er generering av testdata svært komplisert. Jeg har nylig jobbet med et prosjekt som måtte injisere testdata til fire forskjellige mikrotjenester, hver som administrerer sin egen database med dataene i hver database relatert til dataene i andre databaser. Det var ganske utfordrende og arbeidskrevende å holde alt i synkronisering.

Vanligvis er det i slike situasjoner lettere å bruke system-APIer og eksisterende verktøy som lager data istedenfor å gå direkte inn i flere datalager og be om at du ikke riper universets stoff. Vi kunne ikke ta denne tilnærmingen fordi vi faktisk trengte å opprette noen ugyldige data med vilje for å teste forskjellige feilforhold og hoppe over noen bivirkninger angående eksterne systemer som skjer under normal arbeidsflyt. 

Konklusjon

I denne opplæringen dekket vi testing mot eksterne datalager, ved hjelp av delte testdatabaser, ved hjelp av øyeblikksbilder av produksjonsdata, og genererer dine egne testdata.

I del fem vil vi fokusere på fuzz-testing, teste hurtigbufferen, teste dataintegritet, teste idempotency og manglende data. Følg med.