Јединично тестирање са Питхон модулом униттест

Važnost i primena jediničnog testiranja u programiranju

Profesionalni programeri nikada ne implementiraju kod bez detaljnog testiranja. Jedinično testiranje predstavlja postupak provere pojedinačnih modula unutar većeg softverskog projekta.

Ovaj tekst objašnjava kako se može sprovesti jedinično testiranje korišćenjem Python-ovog modula unittest. Najpre, hajde da razmotrimo različite vrste testiranja softvera.

U oblasti testiranja, postoje dve glavne kategorije: ručno i automatsko testiranje. Ručno testiranje podrazumeva da ljudi ručno vrše provere nakon završetka razvoja softvera. S druge strane, automatsko testiranje uključuje upotrebu programa koji automatski sprovode testove i pružaju rezultate.

Ručno testiranje je vremenski zahtevno i teško ga je dosledno primenjivati. Zbog toga, programeri pišu kod za izvođenje testova automatski. Postoji nekoliko vrsta automatskog testiranja, uključujući jedinično testiranje, integraciono testiranje, end-to-end testiranje, testiranje pod opterećenjem i druge.

Razmotrimo standardni tok testiranja:

  • Napišite ili izmenite izvorni kod.
  • Napišite ili ažurirajte testove za razne scenarije vašeg koda.
  • Pokrenite testove (ručno ili pomoću alata za pokretanje testova).
  • Analizirajte rezultate testova. Ako postoje greške, ispravite ih i ponovite postupak.

U nastavku ćemo se usredsrediti na najosnovniji tip testiranja – jedinično testiranje. Bez daljeg odlaganja, krenimo sa praktičnim uputstvom.

Šta je jedinično testiranje?

Jedinično testiranje predstavlja metodu testiranja manjih, nezavisnih delova koda. Najčešće, taj mali blok koda je funkcija. Nezavisnost znači da taj deo koda ne zavisi od drugih komponenti projekta.

Na primer, pretpostavimo da treba da verifikujemo da li je string jednak „vdzvdz“. Napisali smo funkciju koja prihvata jedan argument i vraća informaciju da li je isti kao „techblog.co.rs“ ili ne.


def is_equal_to_geekflare(string):
    return string == "techblog.co.rs"
  

Navedena funkcija nema zavisnosti od drugog koda. Stoga, možemo je testirati nezavisno koristeći različite ulazne vrednosti. Takav nezavisan deo koda može se koristiti u celom projektu.

Značaj jediničnog testiranja

Uglavnom, takvi nezavisni delovi koda se koriste više puta u celom projektu. Zbog toga, moraju biti dobro napisani i detaljno testirani. Jedinični testovi se koriste za testiranje ovih nezavisnih blokova koda. Šta bi se desilo kada ne bismo koristili jedinične testove?

Pretpostavimo da nismo testirali male blokove koda koji se koriste u celom projektu. Tada bi svi ostali testovi, kao što su integracioni testovi i end-to-end testovi, koji koriste te iste blokove, mogli da padnu. To može dovesti do kvara aplikacije. Zbog toga je ključno dobro testirati osnovne blokove koda.

Sada razumemo važnost jediničnog testiranja i pisanja testova za sve nezavisne blokove koda. Kada se jedinični testovi sprovedu, ostali testovi neće padati zbog problema sa tim nezavisnim blokovima koda.

U narednim delovima, razmotrićemo šta je Python modul unittest i kako ga koristiti za pisanje jediničnih testova u Pythonu.

Napomena: Pretpostavlja se da ste upoznati sa Python klasama, modulima itd. Ukoliko nemate iskustva sa srednjim konceptima Pythona, kao što su klase i moduli, možda će vam biti teško da razumete naredne delove.

Šta je Python unittest?

Python unittest je ugrađeni okvir za testiranje Python koda. On ima pokretač testova koji omogućava lako izvršavanje testova. Dakle, možemo koristiti ugrađeni unittest modul za testiranje bez potrebe za modulima treće strane. Naravno, to zavisi od vaših potreba. Ugrađeni unittest modul je odličan za početak testiranja u Pythonu.

Da bismo testirali Python kod koristeći unittest modul, potrebno je da sledimo sledeće korake:

#1. Napišite kod.

#2. Uvezite unittest modul.

#3. Napravite datoteku čije ime počinje sa ključnom rečju test, na primer test_primer.py. Ključna reč test se koristi za prepoznavanje datoteka sa testovima.

#4. Napravite klasu koja nasleđuje unittest.TestCase klasu.

#5. Napišite metode (testove) unutar klase. Svaka metoda sadrži različite test slučajeve zasnovane na vašim potrebama. Metoda mora da počinje ključnom rečju test.

#6. Pokrenite testove. Testovi se mogu pokrenuti na različite načine:

  • Pokretanjem komande python -m unittest test_ime_datoteke.py.
  • Pokretanjem test datoteka kao obične Python datoteke pomoću komande python test_ime_datoteke.py. Da bi ovaj metod funkcionisao, potrebno je da pozovemo main metodu modula unittest unutar test datoteke.
  • Korišćenjem metode otkrivanja. Testove možemo automatski pokrenuti koristeći komandu python -m unittest discover bez navođenja imena test datoteke. Ona će pronaći testove na osnovu konvencije imenovanja koju koristimo. Dakle, imena datoteka sa testovima moraju počinjati ključnom rečju test.

U testiranju, obično upoređujemo izlaz koda sa očekivanim rezultatom. Za poređenje izlaza, unittest modul nudi različite metode. Listu funkcija za poređenje možete pronaći ovde.

Veoma su jednostavne i lako se razumeju.

Dosta teorije, sada je vreme za kodiranje.

Napomena: Ukoliko imate pitanja o unittest modulu, posetite zvaničnu dokumentaciju. Bez daljeg odlaganja, hajde da upotrebimo unittest modul.

Jedinični testovi u Pythonu pomoću unittesta

Prvo ćemo napisati nekoliko funkcija, a zatim se fokusirati na pisanje testova. Otvorite folder u omiljenom editoru koda i kreirajte datoteku pod nazivom utils.py. Ubacite sledeći kod u datoteku:


import math

def is_prime(n):
    if n < 0:
        return 'Negative numbers are not allowed'
    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 "Hello, " + name

U datoteci utils.py imamo tri različite funkcije. Sada, moramo da testiramo svaku funkciju koristeći različite scenarije. Hajde da napišemo testove za prvu funkciju is_prime.

#1. Kreirajte datoteku pod imenom test_utils.py u istom folderu kao utils.py.

#2. Uvezite module utils i unittest.

#3. Kreirajte klasu pod imenom TestUtils koja nasleđuje klasu unittest.TestCase. Ime klase može biti proizvoljno, ali je dobro da bude opisno.

#4. Unutar klase napišite metodu pod imenom test_is_prime koja prihvata self kao argument.

#5. Napišite različite testne slučajeve sa argumentima za is_prime i uporedite izlaz sa očekivanim rezultatom.

#6. Primer test slučaja je self.assertFalse(utils.is_prime(1)).

#7. Očekujemo da će izlaz is_prime(1) biti netačan u navedenom slučaju.

#8. Slično kao u prethodnom slučaju, testiraćemo različite slučajeve u zavisnosti od funkcije koju testiramo.

Pogledajmo sada testove:


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),
                         "Negative numbers are not allowed")

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

Pozivamo main metodu unittest modula da bismo pokrenuli testove pomoću komande python ime_datoteke.py. Sada pokrenite testove.

Videćete izlaz sličan onom ispod:


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

OK

Sada, pokušajte da napišete testne slučajeve i za druge funkcije. Razmotrite različite scenarije za funkcije i napišite testove za njih. U nastavku su dati testovi dodati u gornju klasu:


...
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("techblog.co.rs"), "Hello, techblog.co.rs")
        self.assertEqual(utils.say_hello("Chandan"), "Hello, Chandan")
        self.assertNotEqual(utils.say_hello("Chandan"), "Hi, Chandan")
        self.assertNotEqual(utils.say_hello("Hafeez"), "Hi, Hafeez")
...

Upotrebili smo samo neke od funkcija za poređenje iz unittest modula. Kompletnu listu možete naći ovde.

Naučili smo kako da pišemo jedinične testove koristeći unittest modul. Sada, vreme je da razmotrimo različite načine za pokretanje testova.

Kako pokrenuti testove koristeći unittest

Već smo videli jedan način za pokretanje testova u prethodnom delu. Razmotrimo preostala dva načina za pokretanje testova koristeći unittest modul.

#1. Korišćenjem imena datoteke i unittest modula.

U ovom metodu, koristimo unittest modul i ime datoteke za pokretanje testova. Komanda za pokretanje testova je python -m unittest ime_datoteke.py. U našem slučaju, komanda za pokretanje testova je python -m unittest test_utils.py.

#2. Korišćenjem metode otkrivanja

Koristimo metodu otkrivanja modula unittest da bismo automatski otkrili sve test datoteke i pokrenuli ih. Da bi se datoteke automatski otkrile, njihova imena moraju počinjati ključnom rečju test.

Komanda za pokretanje testova pomoću metode otkrivanja je python -m unittest discover. Komanda će otkriti sve datoteke čija imena počinju sa test i izvršiti ih.

Zaključak

Jedinični testovi su temeljno testiranje u svetu programiranja. Postoji mnogo drugih testova u praksi, koje treba postepeno savladavati. Nadamo se da vam je ovo uputstvo pomoglo da napišete osnovne testove u Pythonu koristeći unittest modul. Postoje i biblioteke treće strane, kao što su pytest, Robot Framework, nose, nose2, i druge. Njih možete istražiti u zavisnosti od zahteva vašeg projekta.

Srećno testiranje! 😎

Možda vas zanimaju i Pitanja i odgovori sa intervjua za Python.