Enhetstestning med Python unittest-modul

By rik

Vikten av grundlig testning i mjukvaruutveckling

En professionell utvecklare publicerar aldrig kod utan att den först genomgått noggranna tester. Enhetstestning, som fokuserar på att kontrollera enskilda moduler i ett större program, är en avgörande del av denna process.

I denna artikel utforskar vi hur du kan utföra enhetstestning av din kod med hjälp av Pythons inbyggda unittest-modul. Låt oss börja med att definiera de olika typerna av tester som finns.

Testning kan i grunden delas in i två kategorier: manuell och automatisk testning. Manuell testning innebär att en person genomför tester efter att utvecklingen är klar, medan automatisk testning innebär att programvara används för att utföra testerna och ge resultaten.

Manuell testning kan vara tidskrävande och svår att hantera, speciellt i större projekt. Därför är automatisk testning, där kod används för att utföra testerna, ett effektivare alternativ. Det finns olika typer av automatisk testning, inklusive enhetstestning, integrationstestning, end-to-end-testning och stresstestning.

Ett typiskt testflöde kan beskrivas med följande steg:

  • Skriv eller uppdatera koden.
  • Skriv eller uppdatera tester för olika scenarier som din kod kan stöta på.
  • Kör testerna (antingen manuellt eller via en testkörningsmotor).
  • Analysera testresultaten. Om fel upptäcks, korrigera dem och upprepa processen.

I denna artikel kommer vi att fokusera på enhetstestning, som är en grundläggande testmetod. Låt oss dyka djupare in i ämnet.

Vad är Enhetstestning?

Enhetstestning är en teknik för att testa små, isolerade kodblock. Oftast rör det sig om enskilda funktioner. Att koden är ”isolerad” innebär att den inte är beroende av andra delar av projektet.

Anta att vi vill kontrollera om en sträng är lika med ”adminvista.com”. För detta kan vi skapa en funktion som tar en sträng som argument och returnerar `True` om den matchar ”adminvista.com”, annars `False`.

def is_equal_to_adminvista(string):
  return string == "adminvista.com"
  

Den här funktionen är oberoende av annan kod, så vi kan testa den separat genom att mata in olika värden. Den isolerade koden kan sedan användas i hela projektet.

Varför är Enhetstestning Viktigt?

Eftersom oberoende kodblock ofta används i hela projektet är det viktigt att säkerställa att de är korrekt skrivna och noggrant testade. Enhetstester används just för detta ändamål. Om vi inte enhetstestar vår kod kan det leda till problem.

Om små, återanvända kodblock inte testas korrekt kan andra tester, som integrationstester och end-to-end-tester, också misslyckas. Detta kan leda till att applikationen går sönder. Det är därför viktigt att testa de grundläggande byggstenarna i koden ordentligt.

Nu när vi vet vikten av enhetstestning och varför alla oberoende kodblock bör testas, kan vi se hur det påverkar andra tester. Eftersom vi har genomfört enhetstester kommer andra tester inte att misslyckas på grund av de otestade kodblocken.

I de kommande avsnitten kommer vi att gå igenom vad Pythons unittest-modul är och hur vi kan använda den för att skapa enhetstester i Python.

Notera: Det antas att du har grundläggande kunskaper om Python-klasser, moduler, etc. Om du inte är bekant med dessa koncept kan det vara svårt att följa de kommande avsnitten.

Introduktion till Python unittest

Python unittest är ett inbyggt testramverk som används för att testa Python-kod. Det inkluderar en testkörningsmotor som förenklar processen med att köra testerna. Du behöver inte använda tredjepartsbibliotek för att börja testa, men det finns alternativ som kan vara bra beroende på dina behov. Det inbyggda unittest-modulen är ett utmärkt ställe att börja lära sig testa i Python.

För att testa din Python-kod med unittest-modulen behöver du följa dessa steg:

  1. Skriv din kod.
  2. Importera unittest-modulen.
  3. Skapa en fil med testfall. Filnamnet ska börja med ordet ”test”, till exempel `test_min_kod.py`.
  4. Skapa en klass som ärver från `unittest.TestCase`.
  5. Skriv testmetoder (som börjar med ”test”) i klassen. Varje testmetod representerar ett specifikt testfall.
  6. Kör testerna.

Det finns flera sätt att köra testerna:

  • Kör kommandot `python -m unittest test_filnamn.py`.
  • Du kan köra testfilen som ett vanligt Python-skript med `python test_filnamn.py`. För att detta ska fungera måste du anropa huvudmetoden i `unittest` i testfilen.
  • Slutligen kan du använda metoden ”discover” för att automatiskt köra alla tester genom kommandot `python -m unittest discover`. Det hittar alla testfiler baserat på filnamnets konventioner.

I praktiken jämför vi output från koden med den förväntade output. För att göra detta tillhandahåller `unittest` olika assertionsmetoder. Du kan se en fullständig lista över dessa metoder här.

De är ganska lätta att förstå.

Nu när vi har gått igenom teorin, låt oss börja skriva kod.

Obs: Om du har frågor om unittest-modulen kan du besöka den officiella dokumentationen.

Enhetstestning i Python med unittest

Först skapar vi några funktioner som vi kommer att testa. Skapa en fil som heter `utils.py` i din favoritkodredigerare och klistra in följande kod:

import math

def is_prime(n):
  if n < 0:
    return 'Negativa tal är inte tillåtna'

  if n <= 1:
    return False

  if n == 2:
    return True

  if n % 2 == 0:
    return False

  for i in range(2, int(math.sqrt(n)) + 1):
    if n % i == 0:
      return False
  return True

def cubic(a):
  return a * a * a

def say_hello(name):
  return "Hej, " + name

Vi har definierat tre funktioner i `utils.py`. Nu ska vi testa varje funktion med olika testfall. Låt oss börja med att testa `is_prime`.

  1. Skapa en fil som heter `test_utils.py` i samma mapp som `utils.py`.
  2. Importera både `utils` och `unittest`-modulerna.
  3. Skapa en klass som heter `TestUtils` och som ärver från `unittest.TestCase`.
  4. Inuti klassen, definiera en metod som heter `test_is_prime` som tar `self` som argument.
  5. Använd olika inputvärden i `is_prime` och jämför resultatet med det förväntade resultatet med hjälp av assertions.
  6. Exempelvis, `self.assertFalse(utils.is_prime(1))` förväntar sig att resultatet från `is_prime(1)` ska vara `False`.
  7. Vi skapar olika testfall baserat på funktionen som vi testar.

Här är koden för testfallen:

import unittest
import utils

class TestUtils(unittest.TestCase):
  def test_is_prime(self):
    self.assertFalse(utils.is_prime(4))
    self.assertTrue(utils.is_prime(2))
    self.assertTrue(utils.is_prime(3))
    self.assertFalse(utils.is_prime(8))
    self.assertFalse(utils.is_prime(10))
    self.assertTrue(utils.is_prime(7))
    self.assertEqual(utils.is_prime(-3), "Negativa tal är inte tillåtna")

if __name__ == '__main__':
    unittest.main()

Vi anropar huvudmetoden i `unittest` för att köra testen när vi anropar filen med `python filename.py`. Kör nu testfilen.

Du bör se en utskrift som liknar den nedan:

$ python test_utils.py
.
----------------------------------------------------------------------
Ran 1 test in 0.001s

OK

Nu kan du prova att skapa testfall för de andra funktionerna. Tänk på olika scenarier och skapa passande tester. Lägg till följande testmetoder i `TestUtils`-klassen:

...
class TestUtils(unittest.TestCase):
    def test_is_prime(self):
        ...

    def test_cubic(self):
        self.assertEqual(utils.cubic(2), 8)
        self.assertEqual(utils.cubic(-2), -8)
        self.assertNotEqual(utils.cubic(2), 4)
        self.assertNotEqual(utils.cubic(-3), 27)

    def test_say_hello(self):
        self.assertEqual(utils.say_hello("adminvista.com"), "Hej, adminvista.com")
        self.assertEqual(utils.say_hello("Chandan"), "Hej, Chandan")
        self.assertNotEqual(utils.say_hello("Chandan"), "Hi, Chandan")
        self.assertNotEqual(utils.say_hello("Hafeez"), "Hi, Hafeez")
...

Vi har bara använt några av assertionsmetoderna från unittest-modulen. Du kan se den fullständiga listan här.

Nu när vi har skapat några enhetstester är det dags att utforska olika sätt att köra testerna.

Hur man kör tester med unittest

Vi har redan sett ett sätt att köra testerna, men låt oss nu se de två andra alternativen:

  1. Använda filnamnet och unittest-modulen:
  2. Här använder vi unittest-modulen och filnamnet för att köra testerna. Kommandot är `python -m unittest filnamn.py`. I vårt fall är kommandot `python -m unittest test_utils.py`.

  3. Använda discover-metoden:
  4. Med discover-metoden i unittest-modulen hittar vi och kör automatiskt alla testfiler. För att det ska fungera måste filnamnen börja med ”test”.

    Kommandot för att köra testen är då `python -m unittest discover`.

Avslutning 👩‍💻

Enhetstester är grundläggande inom mjukvaruutveckling. Det finns många andra testmetoder, och du kan lära dig dem successivt. Jag hoppas att den här guiden har hjälpt dig att skriva grundläggande tester i Python med hjälp av unittest-modulen. Du kan även utforska tredjepartsbibliotek som `pytest`, `Robot Framework`, `nose`, `nose2`, `slash` beroende på dina projektkrav.

Lycka till med testningen! 😎

Du kanske också är intresserad av Python-intervjufrågor och svar.