20TD02U_ForAlle_Blooms_Side7_Debugging - itnett/FTD02H-N GitHub Wiki

+++markdown

🐞 Debugging, Testing og Unntaksbehandling: En Helhetlig Reise

Introduksjon

Debugging, testing, og unntaksbehandling er avgjørende prosesser for å sikre at programvaren din er robust, fungerer som forventet, og håndterer feil på en kontrollert måte. Denne veiledningen tar deg med på en dypgående reise gjennom disse tre essensielle komponentene, fra grunnleggende konsepter til avanserte teknikker og beste praksis.

🔍 Debugging: Finne og Fikse Feil

🐞 Hva er Debugging?

Debugging er prosessen med å identifisere, analysere og fikse feil (bugs) i programmet. Feil kan være alt fra syntaxfeil til logiske feil som forårsaker uventet oppførsel.

🛠 Verktøy og Teknikker for Debugging

  1. Print-debugging:

    • En enkel teknikk der du legger til print-setninger i koden for å inspisere verdiene av variabler og programflyten.

    Eksempel:

    def addisjon(a, b):
        print(f"a: {a}, b: {b}")  # Print for å inspisere verdier
        return a + b
    
    resultat = addisjon(5, 3)
    print(resultat)
    
  2. Bruk av en Debugger:

    • En debugger er et verktøy som lar deg kjøre koden trinnvis, sette stoppunkter, og inspisere programtilstanden.

    Eksempel med Python Debugger (pdb):

    import pdb
    
    def addisjon(a, b):
        pdb.set_trace()  # Start en debugger her
        return a + b
    
    resultat = addisjon(5, 3)
    print(resultat)
    

    I dette eksemplet vil pdb.set_trace() stoppe programmet og la deg inspisere tilstanden.

  3. Logging:

    • Logging er en mer sofistikert form for print-debugging som gir mulighet for å skrive ut meldinger til loggfiler. Dette er nyttig i større systemer hvor du trenger en historikk av hendelser.

    Eksempel:

    import logging
    
    logging.basicConfig(level=logging.INFO)
    
    def addisjon(a, b):
        logging.info(f"Legger sammen {a} og {b}")
        return a + b
    
    resultat = addisjon(5, 3)
    logging.info(f"Resultat: {resultat}")
    
  4. Profileringsverktøy:

    • Disse verktøyene hjelper deg med å finne flaskehalser i koden ved å måle tidsbruken til forskjellige deler av programmet.

    Eksempel med cProfile:

    python -m cProfile -s time ditt_program.py
    

    Dette kommandolinjeverktøyet profilerer programmet og viser hvilke funksjoner som tar mest tid.

🧪 Testing: Sikre Kvalitet og Robusthet

📋 Hva er Testing?

Testing er prosessen med å verifisere at koden din fungerer som forventet. Det inkluderer å sjekke at den gir riktig utdata for gitte inndata og håndterer kanttilfeller og feil riktig.

🧪 Typer av Tester

  1. Enhetstesting (Unit Testing):

    • Test av individuelle funksjoner eller metoder for å sikre at de fungerer korrekt isolert.

    Eksempel med unittest:

    import unittest
    
    def addisjon(a, b):
        return a + b
    
    class TestMatte(unittest.TestCase):
        def test_addisjon(self):
            self.assertEqual(addisjon(5, 3), 8)
            self.assertEqual(addisjon(-1, 1), 0)
    
    if __name__ == '__main__':
        unittest.main()
    
  2. Integrasjonstesting:

    • Test av kombinasjoner av moduler eller funksjoner for å sikre at de fungerer sammen som forventet.

    Eksempel:

    Tenk deg at du har en funksjon som avhenger av flere andre funksjoner. En integrasjonstest vil sjekke at hele kjeden fungerer:

    def test_innlogging_system():
        bruker = opprett_bruker("testbruker", "passord123")
        innlogget = logg_inn("testbruker", "passord123")
        assert innlogget == True
    
  3. Systemtesting:

    • Test av hele systemet som en enhet for å sikre at alt fungerer sammen i en reell brukssetting.

    Eksempel:

    Dette kan innebære å kjøre et script som tester hele applikasjonen fra start til slutt, inkludert bruk av eksterne tjenester.

  4. Godkjennelsestesting (Acceptance Testing):

    • Test som sikrer at systemet oppfyller kravene og fungerer som forventet for sluttbrukeren.

    Eksempel:

    Dette kan inkludere automatiserte tester som kjører brukerhistorier eller manuelle tester der faktiske brukere prøver systemet.

🔄 Testdreven Utvikling (TDD)

Testdreven utvikling er en metode der du skriver tester før du skriver koden. Dette sikrer at du alltid utvikler kode som oppfyller spesifikke krav og er dekket av tester.

Trinn i TDD:

  1. Skriv en enhetstest som feiler fordi funksjonen ikke eksisterer ennå.
  2. Skriv nok kode til at testen akkurat passerer.
  3. Refaktorer koden for å forbedre strukturen mens du sørger for at testen fortsatt passerer.

Eksempel:

def test_addisjon():
    assert addisjon(5, 3) == 8  # Test som vil feile fordi addisjon() ikke er definert

def addisjon(a, b):
    return a + b  # Skriv koden for å få testen til å passere

# Refaktorering (hvis nødvendig) uten å bryte testen

⚠️ Unntaksbehandling: Håndtering av Feil på en Kontrollerbar Måte

🚨 Hva er Unntaksbehandling?

Unntaksbehandling er mekanismen som brukes for å håndtere uventede feil eller unntak som oppstår under programkjøring. I stedet for at programmet krasjer, kan det fange opp unntaket og håndtere det på en kontrollert måte.

🛠 Try-Except-Finally

try-except-blokken brukes til å håndtere unntak som kan oppstå i koden.

Eksempel på Grunnleggende Unntaksbehandling:

def del_tall(a, b):
    try:
        resultat = a / b
    except ZeroDivisionError:
        print("Feil: Kan ikke dele på null!")
        resultat = None
    finally:
        print("Ferdig med divisjon.")
    return resultat

print(del_tall(10, 2))  # Utdata: 5.0
print(del_tall(10, 0))  # Utdata: Feil: Kan ikke dele på null!

🎯 Bruk av Egendefinerte Unntak

Du kan også definere dine egne unntak for å gjøre feilhåndteringen mer spesifikk og relevant for din applikasjon.

Eksempel:

class MinEgendefinertFeil(Exception):
    pass

def sjekk_verdi(verdi):
    if verdi < 0:
        raise MinEgendefinertFeil("Verdi kan ikke være negativ!")
    return True

try:
    sjekk_verdi(-1)
except MinEgendefinertFeil as e:
    print(e)  # Utdata: Verdi kan ikke være negativ!

🎛 Best Practices for Unntaksbehandling

  1. Ikke svelg unntak:

    • Unngå å bruke bare en generell except-blokk uten å håndtere eller logge unntaket.

    Dårlig praksis:

    try:
        resultat = a / b
    except:
        pass  # Dårlig praksis: Ignorerer unntaket fullstendig
    
  2. Spesifikke unntak:

    • Håndter spesifikke unntak som kan forventes, slik at du ikke utilsiktet undertrykker andre feil.

    God praksis:

    try:
        resultat = a / b
    except ZeroDivisionError:
        print("Feil: Kan ikke dele på null!")
    
  3. Bruk endelig-blokker:

    • Bruk finally-blokken for å utføre kode som må kjøre uansett om det oppstår et unntak eller ikke (f.eks. lukking av filer eller frigjøring av ressurser).

    Eksempel:

    try:
        fil = open("data.txt", "r")
        data = fil.read()
    except FileNotFoundError:
        print("Filen ble ikke funnet!")
    finally:
        fil.close()
    

🎯 Konklusjon

Debugging, testing, og unntaksbehandling er grunnleggende ferdigheter som enhver utvikler må mestre for å sikre kvaliteten og robustheten til programvaren. Ved å forstå og anvende disse teknikkene kan du ikke bare finne og fikse feil, men også forhindre dem, sikre at koden din fungerer som den skal, og håndtere uventede situasjoner på en kontrollert måte.


Opprettet og optimalisert for Github Wiki. Følg med for flere dyptgående veiledninger om beste praksis for debugging, testing, og unntaksbehandling i programvareutvikling. +++