Hvorfor teste?
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å | Type | Hastighet | Kostnad | Mengde |
|---|---|---|---|---|
| Topp | Systemtest / E2E | Treg | Dyrt | Få |
| Midten | Integrasjonstest | Middels | Middels | Noen |
| Bunn | Enhetstest | Rask | Billig | Mange |
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
| Egenskap | Enhetstesting | Integrasjonstesting |
|---|---|---|
| Hva testes | Én funksjon/klasse isolert | Samspillet mellom komponenter |
| Avhengigheter | Mockes/stubbes ut | Reelle avhengigheter brukes |
| Hastighet | Meget rask (millisekunder) | Tregere (sekunder) |
| Vedlikehold | Enklere å vedlikeholde | Mer kompleks oppsett |
| Finner | Feil i logikk | Feil i grensesnitt/integrasjon |
| Kjøres | Kontinuerlig i CI | I CI, men gjerne sjeldnere |
TDD – Test Driven Development
TDD er en test-first tilnærming: tester skrives FØR koden implementeres.
Red-Green-Refactor syklusen
-
R
Red – Skriv en test som feiler
Skriv en test for ønsket funksjonalitet. Testen feiler fordi koden ikke er implementert ennå.
-
G
Green – Implementer minste mulig kode
Skriv akkurat nok kode til at testen passerer. Ikke mer.
-
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:
Given [forutsetning]
When [handling]
Then [forventet resultat]
TDD vs. BDD
| Egenskap | TDD | BDD |
|---|---|---|
| Fokus | Enhetstester, kode-nivå | Akseptansetester, bruker-nivå |
| Involverte | Utviklere | Dev + tester + PO |
| Språk | Programmeringsspråk | Gherkin (naturlig språk) |
| Nivå | Lavt (unit) | Høyt (feature/acceptance) |
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
- Utvikler pusher kode / åpner pull request
- CI-systemet kjører alle tester automatisk
- Rapport leveres i pull requesten
- 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
- Finn forventet last (antall brukere, transaksjoner/sek)
- Test i produksjonslikt miljø
- Identifiser hva som feiler/bremser først
- Vurder hva som kan skaleres opp (horisontalt/vertikalt)