Tilbake
3.9
Feilsøking og testing av programmer

3.9 Feilsøking og testing av programmer

Systematisk feilsøking, debugging-teknikker og testing av programkode.

50 min
5 oppgaver
DebuggingSyntaksfeilLogiske feilTestmetoderFeilmeldinger
Du leser den tradisjonelle versjonen
Din fremgang i kapitlet
0 / 5 oppgaver

Feilsøking og testing

Alle programmerere lager feil – det er en helt naturlig del av utviklingsprosessen. Forskjellen mellom en nybegynner og en erfaren programmerer er ikke at den erfarne lager færre feil, men at den erfarne er bedre til å finne og rette dem.

Det finnes tre hovedtyper feil i programmer:
1. Syntaksfeil – brudd på programmeringsspråkets regler
2. Kjøretidsfeil – feilen oppstår når programmet kjøres
3. Logiske feil – programmet kjører uten feilmeldinger, men gir feil resultat

I dette kapittelet skal du lære:
- Hvordan du skiller mellom de tre feiltypene
- Systematisk feilsøking med print-debugging
- Hvordan du leser og tolker feilmeldinger
- Testing med assert og edge cases

Tre typer feil
Syntaksfeil (SyntaxError)
Oppstår når koden bryter reglene i programmeringsspråket. Programmet starter ikke engang.

# Manglende kolon etter if
if x > 5
    print("Stor")  # SyntaxError: expected ':'

# Feil innrykk
def beregn():
print("Hei")       # IndentationError: expected an indented block

Kjøretidsfeil (RuntimeError)
Programmet starter, men krasjer underveis.

tall = [1, 2, 3]
print(tall[5])      # IndexError: list index out of range

resultat = 10 / 0   # ZeroDivisionError: division by zero

alder = int("hei")  # ValueError: invalid literal for int()

Logiske feil
Programmet kjører uten feilmeldinger, men gir feil resultat. Disse er vanskeligst å finne!

# Skal beregne gjennomsnitt, men glemmer parenteser
gjennomsnitt = sum_tall / antall + 1  # Feil: deler bare sum_tall
gjennomsnitt = sum_tall / (antall + 1)  # Riktig: deler på (antall + 1)
✏️Identifisere feiltyper

Klassifiser følgende feil som syntaksfeil, kjøretidsfeil eller logisk feil:

1. print("Hei" (manglende parentes)
2. Et program som beregner arealet av en sirkel med areal = 2 * pi * r i stedet for pi * r**2
3. navn = input("Navn: ") etterfulgt av print(navn + 10)

1. Syntaksfeil – manglende avsluttende parentes er et brudd på Python-syntaksen. Python vil gi SyntaxError: '(' was never closed og programmet vil ikke starte.

2. Logisk feil – formelen 2 * pi * r er omkretsen, ikke arealet. Programmet kjører uten feilmeldinger, men gir feil svar. Dette er den vanskeligste feiltypen fordi Python ikke kan vite hva du mente å skrive.

3. Kjøretidsfeil – du kan ikke legge sammen en streng (navn) og et tall (10) i Python. Programmet starter og venter på input, men krasjer med TypeError når det forsøker å utføre addisjonen.

📝Oppgave 1

Hvilken type feil er det når programmet kjører uten feilmeldinger, men gir feil resultat?

Print-debugging

Den enkleste og mest brukte feilsøkingsteknikken er å legge inn print-setninger for å se hva som skjer inne i programmet.

Strategi:
1. Identifiser hvor feilen trolig oppstår
2. Legg inn print()-setninger for å vise variabelverdier
3. Kjør programmet og analyser utskriften
4. Flytt/legg til print-setninger for å snevre inn feilen
5. Fjern print-setninger når feilen er funnet

Eksempel – feilsøke en beregning:

def beregn_karakter(poeng, maks_poeng):
    prosent = poeng / maks_poeng * 100
    print(f"DEBUG: poeng={poeng}, maks={maks_poeng}, prosent={prosent}")

    if prosent >= 90:
        return 6
    elif prosent >= 75:
        return 5
    elif prosent >= 55:
        return 4
    elif prosent >= 40:
        return 3
    elif prosent >= 20:
        return 2
    else:
        return 1

karakter = beregn_karakter(45, 60)
print(f"DEBUG: karakter={karakter}")

Tips: Bruk prefikset DEBUG: på feilsøkingsutskrifter, slik at de er lette å finne og fjerne etterpå.

✏️Finne en logisk feil med print-debugging

Følgende program skal finne det største tallet i en liste, men gir feil resultat. Bruk print-debugging til å finne feilen.

def finn_storst(tall):
    storst = 0
    for t in tall:
        if t > storst:
            storst = t
    return storst

resultat = finn_storst([-3, -1, -7, -2])
print(resultat)  # Forventer -1, men får 0

Vi legger inn print-setninger for å se hva som skjer:

def finn_storst(tall):
    storst = 0
    print(f"DEBUG: startverdi storst={storst}")
    for t in tall:
        print(f"DEBUG: sjekker {t} > {storst} => {t > storst}")
        if t > storst:
            storst = t
    return storst

Utskrift:

DEBUG: startverdi storst=0
DEBUG: sjekker -3 > 0 => False
DEBUG: sjekker -1 > 0 => False
DEBUG: sjekker -7 > 0 => False
DEBUG: sjekker -2 > 0 => False

Feilen: Startverdien storst = 0 er større enn alle negative tall! Ingen verdier erstatter den.

Løsning: Sett storst = tall[0] (første element) i stedet for 0:

def finn_storst(tall):
    storst = tall[0]  # Bruk første element som startverdi
    for t in tall[1:]:
        if t > storst:
            storst = t
    return storst

📝Oppgave 2

Følgende program skal beregne summen av alle partall i en liste, men gir feil resultat. Finn feilen og forklar den.

def sum_partall(tall):
    total = 0
    for t in tall:
        if t % 2 == 1:
            total += t
    return total

resultat = sum_partall([1, 2, 3, 4, 5, 6])
print(resultat)  # Forventer 12, men får 9

Systematisk feilsøking

Erfarne programmerere følger en systematisk fremgangsmåte for feilsøking:

Steg 1: Les feilmeldingen nøye
Python-feilmeldinger inneholder verdifull informasjon:

Traceback (most recent call last):
  File "program.py", line 5, in <module>
    resultat = tall[10]
IndexError: list index out of range
- Filen og linjenummeret: line 5 – feilen er på linje 5
- Feiltypen: IndexError – indeksen er utenfor listens rekkevidde
- Beskrivelsen: list index out of range – du prøver å hente et element som ikke finnes

Steg 2: Isoler feilen
- Kommenter ut deler av koden for å finne hvor feilen oppstår
- Test med enkle, kjente inputverdier
- Reduser problemet til den minste koden som reproduserer feilen

Steg 3: Forstå feilen
- Hva forventet du at koden skulle gjøre?
- Hva gjør koden faktisk?
- Hva er forskjellen?

Steg 4: Rett feilen og test
- Gjør én endring om gangen
- Test med flere ulike inputverdier
- Kontroller at rettelsen ikke introduserer nye feil

📝Oppgave 3

Du får feilmeldingen:

Traceback (most recent call last):
  File "sensor.py", line 12, in <module>
    temperatur = int(svar)
ValueError: invalid literal for int() with base 10: 'tjueto'
Hva er mest sannsynlig årsak til feilen?

Testing med assert

assert er et Python-nøkkelord som sjekker om en betingelse er sann. Hvis betingelsen er usann, krasjer programmet med en AssertionError.

def beregn_areal(lengde, bredde):
    return lengde * bredde

# Tester
assert beregn_areal(5, 3) == 15, "5 × 3 skal gi 15"
assert beregn_areal(0, 10) == 0, "0 × 10 skal gi 0"
assert beregn_areal(2.5, 4) == 10.0, "2.5 × 4 skal gi 10.0"
print("Alle tester bestått!")

Edge cases – grensetilfeller som ofte avslører feil:
- Tom liste eller streng
- Null (0) som input
- Negative tall
- Svært store tall
- Samme verdi for alle input

def gjennomsnitt(tall):
    if len(tall) == 0:
        return 0  # Håndter tom liste
    return sum(tall) / len(tall)

# Test med edge cases
assert gjennomsnitt([10]) == 10        # Bare ett element
assert gjennomsnitt([]) == 0           # Tom liste
assert gjennomsnitt([-5, 5]) == 0      # Positive og negative
assert gjennomsnitt([3, 3, 3]) == 3    # Alle like
print("Alle tester bestått!")
✏️Skrive tester for en funksjon

Skriv tester med assert for funksjonen er_gyldig_alder(alder) som returnerer True hvis alderen er mellom 0 og 150.

def er_gyldig_alder(alder):
    return 0 <= alder <= 150

# Vanlige tilfeller
assert er_gyldig_alder(25) == True, "25 er gyldig"
assert er_gyldig_alder(0) == True, "0 er gyldig"
assert er_gyldig_alder(150) == True, "150 er gyldig"

# Ugyldige verdier
assert er_gyldig_alder(-1) == False, "-1 er ugyldig"
assert er_gyldig_alder(151) == False, "151 er ugyldig"
assert er_gyldig_alder(-100) == False, "-100 er ugyldig"

# Edge cases - grenseverdier
assert er_gyldig_alder(1) == True, "1 er gyldig"
assert er_gyldig_alder(149) == True, "149 er gyldig"

print("Alle tester bestått!")

Vi tester:
- Vanlige verdier som vi vet skal gi True eller False
- Grenseverdier (0, 1, 149, 150, 151, -1) som er der feil ofte oppstår
- Ekstremt ugyldige verdier for å være sikre

📝Oppgave 4

Skriv en funksjon er_partall(tall) som returnerer True hvis tallet er partall, og False ellers. Skriv deretter minst 5 assert-tester som dekker vanlige tilfeller og edge cases.

Oppsummering

I dette kapittelet har du lært systematisk feilsøking og testing:

- Syntaksfeil – brudd på språkets regler, oppdages før programmet starter
- Kjøretidsfeil – programmet krasjer under kjøring (IndexError, TypeError, osv.)
- Logiske feil – programmet gir feil resultat uten feilmeldinger
- Print-debugging – legg inn print() for å se hva som skjer inne i koden
- Systematisk feilsøking – les feilmelding → isoler → forstå → rett → test
- assert – sjekk at funksjoner gir riktig resultat med kjente inputverdier
- Edge cases – test med grenseverdier som tomme lister, null og negative tall

Nøkkelbegreper


BegrepForklaring
SyntaksfeilBrudd på programmeringsspråkets regler
KjøretidsfeilFeil som oppstår når programmet kjøres
Logisk feilProgrammet gir feil resultat uten feilmeldinger
Print-debuggingBruke print() til å vise variabelverdier under feilsøking
assertSjekker at en betingelse er sann, krasjer hvis ikke
Edge caseGrensetilfelle som kan avsløre feil (tom liste, 0, negative tall)
📝Oppgave 5

Følgende program har tre feil – én syntaksfeil, én kjøretidsfeil og én logisk feil. Finn og rett alle tre. Forklar hvilken type feil hver av dem er.

def beregn_statistikk(malinger)
    antall = len(malinger)
    gjennomsnitt = sum(malinger) / antall
    avvik = []
    for i in range(antall + 1):
        avvik.append(malinger[i] - gjennomsnitt)
    total_avvik = sum(avvik) / antall
    return gjennomsnitt, total_avvik

resultat = beregn_statistikk([20, 22, 25, 21, 23])
print(f"Gjennomsnitt: {resultat[0]}, Avvik: {resultat[1]}")

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.