Hvorfor teste?

Eksamensfokus Oppgave 3 på eksamen (2023) handlet om forskjellen mellom enhetstesting og integrasjonstesting, og testdrevet utvikling (TDD). Kjenn disse godt.

Vi tester programvare for å validere at systemet:

  • Responderer riktig ved interaksjon/input
  • Ikke har bugs eller andre feil
  • Har god nok ytelse, selv ved høyt press
  • Møter krav til brukervennlighet
  • Møter kravene satt av interessenter/product owner
  • Kan installeres i riktig miljø
  • Ikke brekker ved endringer

Testpyramiden

Testpyramiden viser forholdet mellom testtyper – både i mengde, hurtighet og kostnad:

NivåTypeHastighetKostnadMengde
ToppSystemtest / E2ETregDyrt
MidtenIntegrasjonstestMiddelsMiddelsNoen
BunnEnhetstestRaskBilligMange
Pyramid-regelen Ha mange raske enhetstester, færre integrasjonstester, og svært få langsomme end-to-end tester. Dette gir raskest mulig feedback ved lavest mulig kostnad.

Viktige testtyper

Enhetstesting
Tester individuelle komponenter/funksjoner i isolasjon. Alltid automatisert. Verktøy: JUnit (Java), pytest (Python).
Integrasjonstesting
Tester samspillet mellom komponenter. F.eks. at service og database kommuniserer riktig.
Systemtesting
Tester hele systemet fra ende til ende. Verifikasjon mot kravspesifikasjon.
Akseptansetesting
Validerer at systemet oppfyller forretningskrav. Ofte utført av PO eller kunden.
Regresjonstesting
Sikrer at ny kode ikke bryter eksisterende funksjonalitet. Kjøres automatisk ved endringer.
Smoke testing
Rask sjekk av kritisk funksjonalitet etter deployment. «Brenner bygget?»
Eksplorativ testing
Ustrukturert manuell testing der testeren utforsker systemet kreativt. Finner uventede bugs.
Destruktiv testing
Kreativ, utforskende testing der man aktivt prøver å få systemet til å feile. Kan ikke automatiseres – krever menneskelig kreativitet og erfaring.
Usability testing
Tester om systemet oppfyller brukerens behov: Har vi laget det brukeren egentlig ønsker? Fungerer brukergrensesnittet?
Ytelsestesting
Tester systemets ytelse under last. Undertyper: last-, stress-, spike- og utholdenhetstest.

Enhetstesting vs. integrasjonstesting

EgenskapEnhetstestingIntegrasjonstesting
Hva testesÉn funksjon/klasse isolertSamspillet mellom komponenter
AvhengigheterMockes/stubbes utReelle avhengigheter brukes
HastighetMeget rask (millisekunder)Tregere (sekunder)
VedlikeholdEnklere å vedlikeholdeMer kompleks oppsett
FinnerFeil i logikkFeil i grensesnitt/integrasjon
KjøresKontinuerlig i CII CI, men gjerne sjeldnere
Utfyller hverandre Enhetstesting finner feil tidlig i individuelle komponenter. Integrasjonstesting finner feil i samspillet. Begge trengs for robust kodebase.

TDD – Test Driven Development

TDD er en test-first tilnærming: tester skrives FØR koden implementeres.

Red-Green-Refactor syklusen

  1. R

    Red – Skriv en test som feiler

    Skriv en test for ønsket funksjonalitet. Testen feiler fordi koden ikke er implementert ennå.

  2. G

    Green – Implementer minste mulig kode

    Skriv akkurat nok kode til at testen passerer. Ikke mer.

  3. R

    Refactor – Forbedre koden

    Rydd opp koden uten å endre oppførselen. Testen skal fortsatt passere.

Fordeler og utfordringer

Fordeler

  • Bedre kodekvalitet og struktur
  • Høy testdekning fra start
  • Raskere feil-feedback
  • Testene fungerer som dokumentasjon
  • Økt tillit til koden

Utfordringer

  • Bratt lærekurve
  • Tidsbruk initialt høyere
  • Testsuiten krever løpende vedlikehold
  • Ikke alltid naturlig for alle typer kode

BDD – Behavior Driven Development

BDD er en utvidelse av TDD som fokuserer på akseptansetester fra sluttbrukerens perspektiv. Involverer utvikler, tester og Product Owner.

Gherkin-språk

BDD-tester skrives i naturlig språk (Gherkin) med strukturen:

Gherkin-struktur Given [forutsetning] When [handling] Then [forventet resultat]

TDD vs. BDD

EgenskapTDDBDD
FokusEnhetstester, kode-nivåAkseptansetester, bruker-nivå
InvolverteUtviklereDev + tester + PO
SpråkProgrammeringsspråkGherkin (naturlig språk)
NivåLavt (unit)Høyt (feature/acceptance)
TDD + BDD = best of both worlds TDD sikrer kodekvalitet på enhetsnivå. BDD sikrer at use cases fungerer fra sluttbrukerens perspektiv. De utfyller hverandre.

Kontinuerlig integrasjon (CI/CD)

Kontinuerlig integrasjon (CI) handler om at utviklere pusher kode hyppig, og at tester kjøres automatisk ved hver endring.

Slik henger CI og smidig utvikling sammen

  • CI muliggjør hyppige releaser
  • Hyppige releaser betyr liten delta per release → enklere å finne bugs
  • Enklere å rulle tilbake ved feil
  • Uten CI er hyppige releaser nesten umulig

CI-pipeline

  1. Utvikler pusher kode / åpner pull request
  2. CI-systemet kjører alle tester automatisk
  3. Rapport leveres i pull requesten
  4. Koden kan merges hvis tester passerer

Risk poker

Risk poker er en teknikk for å prioritere testinnsats basert på risiko. Hele teamet scorer sannsynligheten og konsekvensen av ulike risikofaktorer med kortstokk.

  • Alle scorer samtidig (som planning poker)
  • Gjennomsnittet beregnes
  • Diskusjon der teammedlemmer er uenige
  • Risiko = sannsynlighet × konsekvens
  • Prioriter testing av høy-risiko-områder

Mocking

Når kode-moduler er avhengige av hverandre, kan det være vanskelig å teste dem isolert. Mocking løser dette ved å erstatte avhengigheter med kontrollerte «dummy»-versjoner.

  • Mocken implementerer samme grensesnitt, men returnerer hardkodede data
  • Gjør det mulig å teste én modul fullstendig isolert
  • Verktøy: Mockito (Java), unittest.mock (Python)
  • NB: Pass på at mock-tester ikke erstatter integrasjonstester

Ytelsestesting

Ytelsestesting verifiserer at systemet tåler forventet last og ikke degraderer under press.

Lasttest (Load test)
Tester systemet under forventet normalbelastning over tid.
Stresstest
Tester jevn, vedvarende last over tid. Finner grensen for kapasiteten.
Spike-test
Tester plutselig, kortvarig last – f.eks. ved populær ticketlansering. Finner hvordan systemet reagerer på unormale topper.
Utholdenhetstest (Stabilitetstest)
Tester jevn, vedvarende last over lang tid. Avslører minnelekkasjer, stigende CPU-bruk og degradering av ytelse over tid.

Fremgangsmåte

  1. Finn forventet last (antall brukere, transaksjoner/sek)
  2. Test i produksjonslikt miljø
  3. Identifiser hva som feiler/bremser først
  4. Vurder hva som kan skaleres opp (horisontalt/vertikalt)

Test testing-kunnskapen din

Øv på spørsmål om testtyper, TDD, BDD og kontinuerlig integrasjon.

Start testing-quiz →