Tilbake
2.8
Feilsøking og testing

2.8 Feilsøking og testing

Lær systematiske metoder for å finne og rette feil i kode, og forstå betydningen av testing for kvalitetssikring.

50 min
6 oppgaver
Syntaksfeil vs. logiske feilDebuggingsverktøyPrint-debuggingEnhetstestingFeilhåndtering med try-except
Du leser den lesevennlige versjonen
Din fremgang i kapitlet
0 / 6 oppgaver

Alle koder feil -- spørsmålet er hva du gjør med det

La oss avlive en myte med en gang: ingen programmerer skriver feilfri kode. Ikke nybegynneren, ikke eksperten med tjue års erfaring. Feil -- eller bugs, som de gjerne kalles -- er en helt naturlig del av å programmere. Selv den mest erfarne utvikler bruker en stor del av tiden sin på å finne og rette feil i koden sin.

Det som skiller en god programmerer fra en frustrert en, er ikke om de lager feil, men hvordan de jakter dem. En dårlig tilnærming er å endre tilfeldig på koden og håpe det hjelper. En god tilnærming er systematisk: forstå hva slags feil det er, finn ut hvor den bor, skjønn hvorfor den oppstår, og rett den. Denne jakten kalles debugging, og det er en ferdighet du kan trene opp.

I denne fortellingen skal vi bli feildetektiver. Vi skal lære å kjenne igjen de tre hovedtypene feil, øve på den systematiske metoden for å finne dem, sette opp try-except som et sikkerhetsnett, og skrive tester som fanger feil før de rekker å gjøre skade. For ordet «ferdig» betyr ingenting hvis koden ikke virker.

Tre slags feil

For å jakte effektivt må du vite hva slags bytte du jakter på. Feil i kode kommer i tre hovedtyper, og de oppfører seg helt ulikt.

Den første og snilleste er syntaksfeil. Dette er feil i selve skrivemåten -- du har brutt Pythons grammatikk, kanskje glemt et kolon, en parentes eller rotet til innrykket. Python nekter rett og slett å kjøre koden og gir deg en feilmelding med en gang. Disse er de enkleste å finne, nettopp fordi maskinen roper ut at noe er galt før programmet i det hele tatt starter.

Den andre er kjøretidsfeil. Her er skrivemåten korrekt, så programmet starter -- men så krasjer det underveis. Typiske eksempler er å prøve int("abc"), som gir en ValueError fordi «abc» ikke er et tall, eller 10 / 0, som gir en ZeroDivisionError fordi vi ikke kan dele på null. Feilen dukker først opp i det øyeblikket den problematiske linjen kjøres.

Den tredje og lumskeste er logisk feil. Nå er det verre, for koden kjører helt fint uten noen feilmelding -- men den gir feil svar. Klassikeren er å skrive a + b / 2 når du mente (a + b) / 2; begge kjører, men bare den ene regner riktig gjennomsnitt. Logiske feil er de vanskeligste å oppdage, fordi maskinen ikke hjelper deg -- den gjør lydig det du faktisk skrev, ikke det du mente.

📝Oppgave Quiz 1

Detektivens metode

Når en feil dukker opp, er fristelsen stor til å endre litt her og litt der i håp om at det løser seg. Men det fører oftest til mer kaos. En ekte feildetektiv jobber systematisk, i fem steg.

Først: reproduser feilen. Klarer du å få den til å skje pålitelig? Hvis du ikke kan gjenskape den, kan du heller ikke vite om du har fikset den. Deretter: isoler den. Finn den minste biten kode som utløser problemet, så slipper du å lete i hele programmet. Så: forstå den. Hvorfor skjer dette? Les feilmeldingen nøye -- den forteller ofte nøyaktig hvilken linje og hva slags feil det er. Først når du forstår årsaken, kan du rette den ordentlig i stedet for å bare lappe over symptomet. Til slutt: test at fiksen faktisk virker, og at du ikke har skapt nye feil på veien.

Et av de enkleste og mest brukte verktøyene i denne jakten er print-debugging. Du strør inn print()-setninger på strategiske steder for å se hva variablene faktisk inneholder underveis. Mistenker du at en rabattfunksjon regner feil, kan du legge inn print(f"DEBUG: pris={pris}, prosent={prosent}") rett før beregningen, og se med egne øyne om verdiene er som forventet. Ofte avslører dette med en gang hvor det går galt -- kanskje var det en variabel som hadde en helt annen verdi enn du trodde.

📝Oppgave Quiz 2

Sikkerhetsnettet og prøvelappen

Noen feil kan vi forutse, men ikke alltid unngå -- som når en bruker skriver bokstaver der vi ventet et tall. Da vil vi ikke at hele programmet skal krasje. Vi vil fange feilen og håndtere den pent. Til det har Python en elegant konstruksjon: try-except.

Tanken er enkel. I try-blokken legger du koden som kan gå galt. I except-blokken legger du hva som skal skje hvis den går galt. Skriver du try: med tall = int(input("Tall: ")) og print(100 / tall), kan du fange to ulike feil: en except ValueError: som griper inn om brukeren skriver noe som ikke er et tall, og en except ZeroDivisionError: som griper inn om de skriver null. I stedet for et stygt krasj får brukeren en vennlig melding, og programmet lever videre. Et godt eksempel er en sikker_divisjon(a, b)-funksjon, som prøver å dele, men returnerer en høflig beskjed i stedet for å krasje hvis nevneren er null.

Men det beste forsvaret mot feil er å fange dem før de når brukeren -- og det gjør vi med enhetstester. I Python kan vi bruke assert, som sjekker om noe er sant. Skriver du assert adder(2, 3) == 5, sier du «jeg påstår at dette skal være sant». Stemmer det, skjer ingenting og programmet går videre. Stemmer det ikke, krasjer det med en feilmelding som forteller deg at noe er galt. Ved å skrive en liten samling slike påstander -- for vanlige tilfeller, for grensetilfeller, for null og negative tall -- bygger du et nett som fanger feil tidlig. Når alle tester går gjennom, kan du faktisk stole på at funksjonen din virker.

📝Oppgave Quiz 3

Oppsummering

Vi har blitt feildetektiver og lært at alle koder feil -- det avgjørende er hvordan vi jakter dem. Vi skiller mellom tre typer: syntaksfeil som bryter grammatikken og stopper koden før start, kjøretidsfeil som krasjer underveis (som deling på null), og de lumske logiske feilene som kjører uten klage, men gir feil svar.

Vi øvde på den systematiske metoden -- reprodusér, isolér, forstå, rett og test -- med print-debugging som et enkelt, kraftig verktøy for å se hva variablene egentlig inneholder. Med try-except bygde vi et sikkerhetsnett som fanger forutsigbare feil og lar programmet leve videre, og med enhetstester og assert fanget vi feil tidlig, før de når brukeren. God feilsøking handler om rotårsak, ikke gjetting -- og om aldri å si «ferdig» før koden faktisk virker.

Dette kapitlet er skrevet av Anthropics toppmodeller (Claude Opus og Claude Fable) og er foreløpig ikke manuelt gjennomgått — kvalitetskontrollen gjøres av uavhengige KI-agenter, og innmeldte feil rettes fortløpende. Funnet en feil? Meld fra, så retter vi den. Les mer om hvordan innholdet lages.