Testiranje softvera · Poglavlje 6 · Sedmica 6

Tehnike bijele kutije

Dio 1 – Kod kao mapa

Dio 2 – Kriteriji pokrivenosti

Dio 3 – Mjerimo: coverage.py

Praksa – Mjerimo pokrivenost DeliveryApp

Materijale priredio Erkan Islamović

erkan.islamovic@eubd.edu.ba · erkan.islamovic@gmail.com

Šta učimo ovog semestra

Petnaest sedmica: svaka ima tri časa teorije i tri časa praktične nastave. Danas: poglavlje 6 (Sedmica 6, označeno). Isti primjer kroz knjigu: DeliveryApp, narudžba N-1001.

Sed.PoglavljeTeorija (3 časa)Praksa (3 časa)
1Zašto testiramoUvodne priče; greška, defekt, otkaz; sedam principa; DeliveryAppTabela očekivanih cijena rukom
2Proces i nivoiTest proces; nivoi i V-model; vrste; statičko testiranjeRecenzija zahtjeva DeliveryApp
3Manuelno testiranjeTest slučaj; izvještaj o defektu; istraživačko testiranjeTest slučajevi za web stranicu
4Automatizovano testiranjeŠta automatizovati; piramida testova; prvi testPrvi pytest
5Jedinično testiranjeAAA; fixture, parametri, izuzeci; TDDTestovi za dostavu i popust
6Bijela kutijaGraf toka; pokrivenost; ciklomatska složenostcoverage.py do 100 % grana
7Tok podatakaDefinicija i upotreba; anomalije; statička analiza, mutacijeruff, mypy, ručna mutacija
8Crna kutijaEkvivalencija i granice; tabela odlučivanja; stanjaLov na pet grešaka

Šta učimo ovog semestra

Sed.PoglavljeTeorija (3 časa)Praksa (3 časa)
9Model i integracijaModel; strategije integracije; APITestClient za API
10Sistemsko testiranjeSistemsko; performanse i sigurnost; prihvatno i BDDLocust, Gherkin
11OO testiranjeStanje objekta; nasljeđivanje; dvojniciNarudzba, unittest.mock
12Paralelne aplikacijeTrka podataka; zastoj; nestabilni testoviNiti, 1000 ponavljanja
13Web aplikacijeWeb i DOM; Playwright; Page Object, pristupačnostPlaywright za DeliveryApp
14Upravljanje testiranjemTest plan i rizik; metrike; CI/CDGitHub Actions
15Alati, AI, projekatPregled alata; AI u testiranju; ISTQBOdbrana projekta
N-1001 je 24,50 € · od 30,00 € dostava je besplatna

Literatura

  1. J. Popović: Priručnik za test inženjere, CET i Računarski fakultet, Beograd, 2023.
  2. Rakić-Skoković: Priručnik za testiranje softvera, Fakultet tehničkih nauka, Novi Sad, 2013.
  3. G. J. Myers: The Art of Software Testing, 2. izdanje, John Wiley & Sons, 2004.
  4. A. P. Mathur: Foundations of Software Testing, Addison-Wesley Professional, 2008.
Priča za početak · Sedmica 6

Priča za početak

Priča za početak

U petak, 21. februara 2014., Apple je izdao malu, neobičnu ispravku za iPhone i iPad: iOS 7.0.6. Opis je imao jednu rečenicu: napadač „u privilegovanom položaju na mreži” mogao je presresti i promijeniti podatke koji su trebali biti zaštićeni. Programeri širom svijeta odmah su otvorili javno objavljen izvorni kod Appleove biblioteke za sigurne veze (SSL/TLS) i za nekoliko sati našli uzrok. U funkciji koja provjerava digitalni potpis servera stajala su, jedan ispod drugog, dva ista reda: goto fail;. Prvi je bio ispravan i pripadao je naredbi if. Drugi je bio višak, vjerovatno nastao pri spajanju izmjena, i izvršavao se uvijek.

Program je zato skakao na kraj funkcije prije nego što bi uopšte provjerio potpis, a promjenljiva err je u tom trenutku imala vrijednost 0, što znači „sve u redu”. Telefon je tako prihvatao lažni server kao pravi: napadač na istoj Wi-Fi mreži u kafiću mogao je glumiti banku ili poštu. Ranjivost je dobila oznaku CVE-2014-1266 i nadimak „goto fail”, a ispravka za Mac računare (OS X 10.9.2) stigla je nekoliko dana kasnije. Najzanimljivije za ovo poglavlje je jedno pitanje koje su tada postavili mnogi: kako niko nije primijetio da se provjera potpisa nikad ne izvrši? Alat koji broji koji su redovi koda izvršeni u testovima pokazao bi da redovi za provjeru potpisa nisu izvršeni nijednom. Taj alat se zove mjerenje pokrivenosti koda, i to je glavna tema ovog poglavlja.

Slika 6.1 – goto fail: ponovljeni red preskače provjeru potpisa; sivi redovi se nikad ne izvrše
Slika 6.1 – goto fail: ponovljeni red preskače provjeru potpisa; sivi redovi se nikad ne izvrše

Zašto ovo poglavlje

U poglavljima 3 do 5 test smo pravili iz pravila: PP-2 kaže koliko košta dostava, pa test provjeri tu cijenu. Nismo gledali unutra, u kod. Tako se radi crnom kutijom i detaljno ćemo je učiti u poglavlju 8. Ovo poglavlje otvara poklopac. Kod cijena_dostave koji smo testirali u poglavljima 4 i 5 sada crtamo kao graf, brojimo njegove puteve i mjerimo koliko ga naši testovi stvarno obilaze. Prvo učimo graf toka kontrole i ciklomatsku složenost. Zatim kriterije pokrivenosti: iskaze, grane, uslove i MC/DC. Na kraju mjerimo pokrivenost alatom coverage.py i vidimo njegovu najvažniju pouku: 100 % pokrivenosti ne znači da grešaka nema.

Riječi ovog poglavlja (1/2)

  • Bijela kutija (white-box, structural testing) – testovi koji se prave i ocjenjuju gledajući kod iznutra.
  • Graf toka kontrole (control flow graph, CFG) – crtež programa: čvorovi su dijelovi koda, strelice su mogući skokovi s jednog na drugi.
  • Odluka (decision) – mjesto gdje program bira put, npr. if; ima ishod DA ili NE.
  • Uslov (condition) – najmanji logički dio odluke; odluka km < 0 or km > 10 ima dva uslova.
  • Ciklomatska složenost V(G) – broj nezavisnih puteva kroz funkciju; računa se kao broj odluka + 1.
  • Bazni put (basis path) – jedan od V(G) puteva od kojih se mogu „sklopiti” svi ostali.

Riječi ovog poglavlja (2/2)

  • Pokrivenost (coverage) – procenat dijelova koda (redova, grana, uslova) koje su testovi izvršili.
  • Pokrivenost iskaza (statement coverage) – koliko je redova koda izvršeno bar jednom.
  • Pokrivenost grana (branch coverage) – koliko je ishoda odluka (DA i NE) izvršeno.
  • MC/DC (Modified Condition/Decision Coverage) – svaki uslov mora bar jednom sam, bez pomoći drugih, promijeniti ishod odluke.
  • Nedostižan kod (dead code, unreachable code) – kod do kojeg program nikad ne može doći.
  • coverage.py – alat za mjerenje pokrivenosti Python koda.

Ciljevi poglavlja

Nakon poglavlja možete:

objasniti razliku između bijele i crne kutije; nacrtati graf toka kontrole za kratku funkciju; izračunati ciklomatsku složenost na dva načina i napisati bazne puteve; razlikovati pokrivenost iskaza, grana, uslova, MC/DC i putanja i reći koja uključuje koju; za odluku s dva uslova napraviti najmanji skup testova za MC/DC; izmjeriti pokrivenost alatom coverage.py i pročitati kolonu „Missing”; dopisati testove tako da pokrivenost grana poraste do 100 %; objasniti zašto 100 % pokrivenosti ne garantuje kod bez grešaka.

Plan poglavlja – Sedmica 6: tri časa teorije i tri časa praktične nastave

ČasSadržajNa času
Teorija 16.1–6.3 Bijela kutija; graf toka kontrole; ciklomatska složenost i bazni puteviGraf funkcije cijena_dostave na tabli
Teorija 26.4–6.7 Pokrivenost iskaza, grana, uslova, MC/DC i putanjaKoliko testova treba za MC/DC?
Teorija 36.8–6.10 coverage.py; od 62 % do 100 %; zašto 100 % nije dovoljnoGreška D-01 koja preživi 100 %
Dio 1 · Sedmica 6

Dio 1 – Kod kao mapa

6.1 Bijela i crna kutija

Zamislite da testirate auto. Možete sjesti, voziti i provjeriti da li koči, da li skreće i koliko troši. Ne znate šta je ispod haube, ali znate šta auto treba da radi. To je crna kutija: test se pravi iz zahtjeva, a unutrašnjost se ne gleda. Druga mogućnost je da otvorite haubu, kao mehaničar, i provjerite svaku cijev i svaki kabl: da li je svaki dio bar jednom proradio. To je bijela kutija (ponekad i „staklena kutija”): test se pravi i ocjenjuje gledajući kod.

Dvije kutije odgovaraju na različita pitanja:

6.1 Bijela i crna kutija

Crna kutijaBijela kutija
Izvor testovazahtjevi i pravila (PP-1 … PP-6)kod: odluke, grane, putevi
PitanjeRadi li program ono što treba?Jesu li testovi obišli sav kod?
Hvatapogrešno ponašanje, zaboravljen slučaj iz pravilakod koji nijedan test ne izvršava, mrtav kod, zaboravljenu granu
Ne hvatakod koji radi nešto što pravilo ne spominjepravilo koje kod uopšte nije implementirao
Ko najčešće raditester, korisnik, analitičarprogramer, uz jedinične testove

Posljednji red tabele je važan. Bijela kutija ne može naći ono čega u kodu nema. Ako je programer zaboravio pravilo PP-4 (besplatna dostava), u kodu nema odluke iznos >= 3000, pa je nema ni u grafu, i bijela kutija ne vidi da nešto fali. Zato se dvije kutije dopunjuju: crnom kutijom napravimo testove iz pravila, a bijelom provjerimo da li su ti testovi obišli sav kod.

Slika iz života: pokrivenost je kao obilazak grada. Poštar koji kaže „obišao sam grad” može misliti na glavnu ulicu. Mapa na kojoj su obojene ulice kojima je zaista prošao odmah pokazuje koje ulice nije vidio. Graf toka kontrole je mapa, a alat za pokrivenost boji ulice.

Ukratko – 6.1 Bijela i crna kutija

  • Crna kutija pravi testove iz zahtjeva, a bijela kutija pravi i ocjenjuje testove gledajući kod.
  • Bijela kutija pokazuje koji dijelovi koda nisu izvršeni ni u jednom testu.
  • Bijela kutija ne može naći pravilo koje uopšte nije programirano, jer ga nema u kodu.
  • Dvije kutije se dopunjuju: testovi iz pravila, provjereni mjerenjem pokrivenosti.

6.2 Graf toka kontrole

Da bismo brojali puteve kroz kod, prvo ga crtamo. Graf toka kontrole ima:

  • čvorove (kružiće): komad koda koji se izvršava bez skretanja, ili jednu odluku;
  • grane (strelice): moguće skokove s jednog komada na drugi;
  • jedan ulaz i jedan izlaz (kraj funkcije, bilo da je return ili raise).

Naša funkcija iz primjeri/pokrivenost/dostava.py je ista kao u DeliveryApp, samo s brojevima umjesto konstanti, da se lakše čita:

def cijena_dostave(udaljenost_km, iznos):
    if udaljenost_km < 0 or udaljenost_km > 10:          # red 6
        raise ValueError("udaljenost izvan zone dostave")  # red 7
    if iznos < 500:                                      # red 8
        raise ValueError("iznos manji od minimalne narudžbe")  # red 9
    if iznos >= 3000:                                    # red 10
        return 0                                         # red 11
    dodatni_km = math.ceil(max(0, udaljenost_km - 3))    # red 12
    return 200 + 50 * dodatni_km                         # red 13

6.2 Graf toka kontrole

Crtamo ga korak po korak (slika 6.2):

  1. Čvor 1 je prva odluka (red 6). Ako je DA, ide se u čvor 2 (raise, red 7) i funkcija završava. Ako je NE, ide se dalje.
  2. Čvor 3 je druga odluka (red 8). DA vodi u čvor 4 (raise, red 9), NE vodi dalje.
  3. Čvor 5 je treća odluka (red 10). DA vodi u čvor 6 (return 0), NE u čvor 7.
  4. Čvor 7 su redovi 12 i 13 zajedno: izvršavaju se uvijek jedan za drugim, bez skretanja, pa su jedan čvor.
  5. Svi završeci (2, 4, 6, 7) vode u zajednički čvor kraj.
Slika 6.2 – Graf toka kontrole funkcije `cijena_dostave`: tri odluke (narandžasto), četiri završetka
Slika 6.2 – Graf toka kontrole funkcije `cijena_dostave`: tri odluke (narandžasto), četiri završetka

6.2 Graf toka kontrole

Brojimo: 8 čvorova (1–7 i kraj) i 10 grana (šest izlaza iz odluka i četiri strelice prema kraju).

Na času

Nacrtajte graf za funkciju popust(iznos, kod) iz deliveryapp.py: if not kod: return 0, pa procenat = …, pa if procenat is None: return 0, pa return min(…). Koliko čvorova i grana ima?

Odgovor: ulaz s prvom odlukom (1), return 0 (2), red s procenat i druga odluka (3), return 0 (4), return min (5) i kraj (6): 6 čvorova; grane 1→2, 1→3, 3→4, 3→5, 2→kraj, 4→kraj, 5→kraj: 7 grana.

Ukratko – 6.2 Graf toka kontrole

  • Graf toka kontrole crta program kao čvorove (komade koda i odluke) i grane (moguće skokove).
  • Redovi koji se uvijek izvršavaju jedan za drugim čine jedan čvor.
  • Svaka odluka if ima dvije izlazne grane, DA i NE.
  • Graf funkcije cijena_dostave ima 8 čvorova i 10 grana.

6.3 Ciklomatska složenost i bazni putevi

Koliko testova treba da bismo „prošli” svaki dio grafa? Odgovor daje ciklomatska složenost, mjera koju je Thomas McCabe predložio 1976. godine. Ona broji nezavisne puteve kroz funkciju. Postoje tri načina da se izračuna, i svi daju isti broj:

\[V(G) = E - N + 2\]

gdje je E broj grana, a N broj čvorova. Za cijena_dostave: V(G) = 10 − 8 + 2 = 4.

Drugi način je lakši za glavu: V(G) = broj odluka + 1. Funkcija ima tri if, pa je V(G) = 3 + 1 = 4.

Treći način je za one koji vole crtati: broj zatvorenih oblasti u grafu + 1 (oblasti koje strelice ograđuju kad se graf nacrta bez presijecanja).

6.3 Ciklomatska složenost i bazni putevi

Šta broj 4 znači u praksi? Postoje 4 bazna puta, a svaki drugi put kroz funkciju može se „sklopiti” od njih. Ako testovi prođu sva četiri, svaka grana grafa izvršena je bar jednom.

6.3 Ciklomatska složenost i bazni putevi

PutČvoroviUlaz testaOčekivanoPravilo
P11 → 2 → kraj−1 km, 10,00 €ValueError „izvan zone”PP-3
P21 → 3 → 4 → kraj5 km, 4,50 €ValueError „minimalne”PP-1
P31 → 3 → 5 → 6 → kraj2,5 km, 32,00 € (N-1002)0,00 €PP-4
P41 → 3 → 5 → 7 → kraj4,2 km, 21,50 € (N-1001)3,00 €PP-2

Primijetite da svaki red ima očekivani rezultat iz pravila, a ne iz koda. Graf nam kaže koje puteve treba proći, a pravilo kaže šta treba dobiti na kraju puta.

Česta zabluda

„Odluka km < 0 or km > 10 je jedan if, dakle jedna odluka.” Za graf s jednim čvorom po if to je tačno i V(G) = 4. Ali or krije dva uslova, i ako graf crtamo tako da svaki uslov ima svoj čvor (kako kompajler zaista radi), dobijamo V(G) = 5. Alati se razlikuju: neki broje or i and, neki ne. Važno je da u timu svi broje isto.

6.3 Ciklomatska složenost i bazni putevi

Zašto testeru treba V(G)?

  1. Najmanji broj testova za puno obilaženje grana. Za V(G) = 4 trebaju nam bar četiri testa (osim kad jedan test slučajno prođe dva puta, što nije moguće u funkciji s raise).
  2. Upozorenje na složen kod. McCabe je predložio da funkcija ne prelazi 10. Funkcija s V(G) = 25 ima 25 nezavisnih puteva; teško je razumjeti, teško testirati i lako je pokvariti. Alat ruff iz poglavlja 7 ima pravilo C901 koje javlja funkcije složenije od zadate granice.
  3. Mjesto za refaktorisanje. Složenu funkciju često je bolje razbiti na nekoliko manjih, svaku s malim V(G), nego pisati 25 testova za jednu.
V(G) = broj odluka + 1. Preko 10 je znak da funkciju treba podijeliti.

Ukratko – 6.3 Ciklomatska složenost i bazni putevi

  • Ciklomatska složenost V(G) broji nezavisne puteve kroz funkciju: V(G) = E − N + 2 = broj odluka + 1.
  • Za cijena_dostave V(G) je 4, ili 5 ako se uslovi u or broje posebno.
  • Četiri bazna puta daju četiri testa koji zajedno izvrše svaku granu grafa.
  • Očekivani rezultat na kraju puta uvijek dolazi iz pravila, a ne iz koda.
  • Funkcija s V(G) većim od 10 teško se testira i obično je treba podijeliti.

Provjeri se

  1. Šta je čvor, a šta grana u grafu toka kontrole? Čvor je komad koda bez skretanja ili jedna odluka; grana je mogući skok s jednog čvora na drugi.
  2. Kolika je V(G) funkcije s pet naredbi if i bez petlji? 5 + 1 = 6.
  3. Koji test prolazi bazni put P3 funkcije cijena_dostave? Narudžba od 30,00 € ili više u zoni, npr. N-1002: 2,5 km i 32,00 €, očekivano 0,00 €.

Odgovori: tipka R ili klik na zamućeno polje.

Dio 2 · Sedmica 6

Dio 2 – Kriteriji pokrivenosti

6.4 Pokrivenost iskaza

Najjednostavnije pitanje je: koliko redova koda je izvršeno bar jednom?

\[\text{pokrivenost iskaza} = \frac{\text{izvršeni iskazi}}{\text{svi iskazi}} \times 100\,\%\]

Iskaz (statement) je jedna naredba: dodjela, if, return, raise, poziv funkcije. Alat coverage.py u fajlu dostava.py broji 10 iskaza: import math, def, tri if, dva raise, return 0, red s dodatni_km i posljednji return. (Red def i import se „izvrše” kad se modul učita.)

Uzmimo samo jedan test, N-1001: 4,2 km i 21,50 €. Kroz koje redove prolazi? Red 6 (NE), red 8 (NE), red 10 (NE), red 12, red 13. Uz import i def to je 7 od 10 iskaza, dakle 70 %. Nisu izvršeni redovi 7, 9 i 11: oba raise i return 0.

Drugi test, N-1002 (2,5 km, 32,00 €), prolazi i kroz red 11. Sada je izvršeno 8 od 10, dakle 80 %, a nedostaju samo redovi 7 i 9: dvije poruke o grešci nikad nisu provjerene.

6.4 Pokrivenost iskaza

Pokrivenost iskaza je ono što bi otkrilo goto fail. U Appleovom kodu redovi s provjerom potpisa poslije duplog goto fail; nisu se izvršavali ni u jednom testu, ni u jednom stvarnom pozivu. Izvještaj o pokrivenosti bi te redove pokazao crveno, s nula izvršenja (slika 6.1). Isti problem mogu pokazati i upozorenja kompajlera za nedostižan kod, ali samo ako su uključena.

Iz stvarnog svijeta

Nakon goto fail mnogi su istakli da bi test koji šalje namjerno lažan potpis odmah pokazao da ga telefon prihvata. Takav test je crna kutija (iz pravila: „lažan potpis mora biti odbijen”), a mjerenje pokrivenosti je bijela kutija (iz koda: „ovaj red nikad nije izvršen”). Svaki od ta dva pristupa sam bi uhvatio grešku. Nijedan nije bio primijenjen.

Ukratko – 6.4 Pokrivenost iskaza

  • Pokrivenost iskaza je procenat naredbi koje su testovi izvršili bar jednom.
  • Test N-1001 sam izvrši 7 od 10 iskaza funkcije cijena_dostave, a s N-1002 to je 8 od 10.
  • Redovi koji se nikad ne izvrše vide se odmah, kao provjera potpisa u goto fail.
  • Pokrivenost iskaza je najslabiji kriterij, ali je bolji nego nikakav.

6.5 Pokrivenost grana (odluka)

Pokrivenost iskaza ima slabu tačku: if bez else. Pogledajte mali primjer iz primjeri/pokrivenost/besplatno.py:

def dostava_s_kodom(cijena, kod):
    if kod == "BESPLATNO":
        cijena = 0
    return cijena

Jedan test, dostava_s_kodom(300, "BESPLATNO") == 0, izvrši sva četiri iskaza: 100 % pokrivenost iskaza. Ali nikad nismo provjerili šta se desi kad kod nije „BESPLATNO”. Da je programer napisao cijena = 0 izvan if (greškom uvukao red manje), ovaj test bi i dalje prolazio, a svi kupci bi dobili besplatnu dostavu.

Zato postoji pokrivenost grana (odluka): svaka odluka mora bar jednom dati DA i bar jednom NE.

6.5 Pokrivenost grana (odluka)

\[\text{pokrivenost grana} = \frac{\text{izvršeni ishodi odluka}}{2 \times \text{broj odluka}} \times 100\,\%\]

Za cijena_dostave imamo 3 odluke, dakle 6 ishoda:

OdlukaDANE
red 6: izvan zone?P1 (−1 km)N-1001, N-1002
red 8: ispod 5,00 €?P2 (4,50 €)N-1001, N-1002
red 10: od 30,00 €?N-1002N-1001

Sam N-1001 daje 3 od 6 ishoda (sve NE), a s N-1002 je 4 od 6. Tek s testovima −1 km i 4,50 € imamo sve ishode.

6.5 Pokrivenost grana (odluka)

Pokrivenost grana uključuje pokrivenost iskaza: ako je svaka grana izvršena, izvršen je i svaki iskaz na njoj. Obrnuto ne važi, kako pokazuje dostava_s_kodom.

Za radoznale

coverage.py u režimu --branch ispiše jedan broj koji spaja oba kriterija: (izvršeni iskazi + izvršene grane) / (svi iskazi + sve grane). Za N-1001 sam: (7 + 3) / (10 + 6) = 10 / 16 = 62,5 %, a alat ispiše 62 %. Za N-1001 i N-1002: (8 + 4) / 16 = 75 %.

Ukratko – 6.5 Pokrivenost grana (odluka)

  • Pokrivenost grana traži da svaka odluka bar jednom da DA i bar jednom NE.
  • if bez else može imati 100 % pokrivenost iskaza, a da grana NE nikad nije izvršena.
  • Pokrivenost grana uključuje pokrivenost iskaza, ali ne i obrnuto.
  • Funkcija cijena_dostave ima 6 ishoda odluka; N-1001 i N-1002 zajedno pokriju 4.

6.6 Pokrivenost uslova i MC/DC

Pogledajmo pažljivije prvu odluku:

if udaljenost_km < 0 or udaljenost_km > 10:

Ona ima dva uslova: A = udaljenost_km < 0 i B = udaljenost_km > 10. Pokrivenost grana traži samo da cijela odluka bude jednom DA i jednom NE. To postižu testovi −1 km (DA) i 5 km (NE). Ali uslov B tada nikad nije bio istinit! Da je programer napisao udaljenost_km > 100 umjesto > 10, ova dva testa ne bi primijetila: 11 km bi se dostavljalo.

Pokrivenost uslova traži da svaki uslov bude bar jednom istinit i bar jednom lažan. To je jače, ali ima zamku: testovi −1 km (A tačno) i 11 km (B tačno) zajedno pokrivaju oba uslova u oba ishoda, ali odluka je u oba slučaja DA. Grana NE uopšte nije izvršena.

6.6 Pokrivenost uslova i MC/DC

Za radoznale

Python računa or kratko (short-circuit): ako je A tačno, B se uopšte ne računa, jer je odluka već DA. Za −1 km Python nikad ne provjeri -1 > 10. Kad govorimo o vrijednosti uslova B u tom testu, mislimo na vrijednost koju bi imao da je izračunat (lažno).

Rješenje koje se koristi u najstrožim oblastima je MC/DC (Modified Condition/Decision Coverage, izmijenjena pokrivenost uslova i odluka). Pravilo zvuči komplikovano, a ideja je jednostavna:

  1. svaka odluka bar jednom DA i bar jednom NE (kao grane);
  2. svaki uslov bar jednom tačan i bar jednom lažan (kao uslovi);
  3. svaki uslov mora bar jednom sam promijeniti ishod odluke, dok ostali uslovi stoje isto.

Treća tačka je srž. Ona dokazuje da svaki uslov zaista nešto radi. Uslov koji nikad sam ne mijenja ishod mogao bi se obrisati, i niko ne bi primijetio.

6.6 Pokrivenost uslova i MC/DC

Za odluku A or B tražimo par testova za A i par za B:

TestkmA: km < 0B: km > 10OdlukaPravilo
T15neneNE (dostavlja se)PP-3
T2−1daneDA (odbijeno)PP-3
T311nedaDA (odbijeno)PP-3
  • Par T1 i T2 pokazuje uslov A: B stoji (ne), A se promijeni s ne na da, i odluka se promijeni s NE na DA.
  • Par T1 i T3 pokazuje uslov B: A stoji (ne), B se promijeni, i odluka se promijeni.

Tri testa za dva uslova. Opšte pravilo: za odluku s n uslova MC/DC obično treba n + 1 testova. Puna kombinatorika, koja se zove pokrivenost višestrukih uslova, traži sve kombinacije, 2ⁿ: za 2 uslova to su 4, za 10 uslova 1024 testa. Kod nas je četvrta kombinacija (A i B tačni u isto vrijeme: km < 0 i km > 10) nemoguća, pa je MC/DC ovdje isto što i sve moguće kombinacije.

6.6 Pokrivenost uslova i MC/DC

Gdje se MC/DC koristi? Avionski standard DO-178C traži MC/DC za softver najvišeg nivoa kritičnosti (nivo A), čiji otkaz može srušiti avion. Slične zahtjeve imaju standardi za automobile i željeznicu. U web aplikaciji za hranu MC/DC se rijetko mjeri formalno, ali način razmišljanja je koristan svuda: za svaki uslov u složenom if zapitajte se „koji test pokazuje da je ovaj uslov potreban?”

Česta zabluda

„MC/DC je samo za avione.” Mjeri se formalno uglavnom tamo, ali greška „pogrešna granica u jednom od dva uslova” (11 km se dostavlja) je obična greška u svakoj aplikaciji, i MC/DC je hvata s tri testa.

Ukratko – 6.6 Pokrivenost uslova i MC/DC

  • Uslov je najmanji logički dio odluke; odluka km < 0 or km > 10 ima dva uslova.
  • Pokrivenost grana ne traži da svaki uslov bude tačan, a pokrivenost uslova ne traži oba ishoda odluke.
  • MC/DC traži da svaki uslov bar jednom sam promijeni ishod odluke, što dokazuje da je potreban.
  • Za odluku s n uslova MC/DC obično treba n + 1 testova, a sve kombinacije 2ⁿ.
  • Avionski standard DO-178C traži MC/DC za najkritičniji softver.

6.7 Pokrivenost putanja i hijerarhija kriterija

Najjači kriterij je pokrivenost putanja: svaki mogući put od ulaza do izlaza mora biti izvršen. U cijena_dostave postoje samo četiri puta (svaki raise i return završava funkciju), pa su putanje isto što i bazni putevi. To je izuzetak.

Čim funkcija ima petlju, broj putanja eksplodira. Zamislite petlju koja prolazi kroz stavke korpe, a u svakoj stavci ima jedan if (npr. „da li je artikal na akciji”). Za korpu od 1 stavke postoje 2 puta, za 2 stavke 4, za 3 stavke 8, za 20 stavki 2²⁰ = 1 048 576 puteva. Za korpu bez gornje granice puteva je beskonačno mnogo. Pokrivenost putanja je zato teorijski ideal, a u praksi se koriste bazni putevi (V(G) testova) i petlje se testuju s 0, 1, 2 i „mnogo” prolaza.

Kriteriji se mogu poredati po snazi (slika 6.3). Strelica znači „uključuje”: ko ispuni gornji kriterij, ispunio je i donji.

Slika 6.3 – Hijerarhija kriterija pokrivenosti: iskazi ⊂ grane ⊂ MC/DC ⊂ višestruki uslovi; putanje uključuju grane
Slika 6.3 – Hijerarhija kriterija pokrivenosti: iskazi ⊂ grane ⊂ MC/DC ⊂ višestruki uslovi; putanje uključuju grane

6.7 Pokrivenost putanja i hijerarhija kriterija

KriterijŠta tražiTestova za cijena_dostave
Iskazisvaki red bar jednom4 (svaki raise i return je poseban red)
Granesvaka odluka DA i NE4
MC/DCsvaki uslov sam mijenja odluku5 (4 bazna + 11 km za uslov B)
Višestruki uslovisve moguće kombinacije uslova5 (kombinacija „km < 0 i km > 10” je nemoguća)
Putanjesvaki put od ulaza do izlaza4

Primijetite red za MC/DC: četiri bazna puta testiraju zonu samo sa −1 km, pa uslov B nikad nije tačan. Peti test, 11 km, je upravo onaj koji test_svi.py iz praktične nastave ima.

Na času

Koliko putanja ima funkcija koja ima tri if jedan ispod drugog, ali bez return i raise unutar njih (svaki if samo promijeni neku promjenljivu)? Koliki je V(G)? – Putanja je 2 × 2 × 2 = 8, a V(G) = 3 + 1 = 4. Bazni putevi su manje od svih putanja: zato je V(G) praktičan kompromis.

Ukratko – 6.7 Pokrivenost putanja i hijerarhija kriterija

  • Pokrivenost putanja traži svaki mogući put, ali petlje čine broj puteva ogromnim ili beskonačnim.
  • U praksi se koriste bazni putevi, a petlje se testiraju s 0, 1, 2 i mnogo prolaza.
  • Kriteriji se poredaju po snazi: iskazi, grane, MC/DC, višestruki uslovi.
  • Jači kriterij traži više testova, ali daje veće povjerenje.

Provjeri se

  1. Može li funkcija imati 100 % pokrivenost iskaza i 50 % grana? Da: if bez else testiran samo s ishodom DA.
  2. Koliko testova treba za MC/DC odluke A or B? Tri: oba lažna, samo A tačan, samo B tačan.
  3. Zašto se pokrivenost putanja rijetko traži u praksi? Jer petlje čine broj putanja ogromnim ili beskonačnim.

Odgovori: tipka R ili klik na zamućeno polje.

Dio 3 · Sedmica 6

Dio 3 – Mjerimo: coverage.py

6.8 Prvo mjerenje

Ručno brojanje je dobro za učenje, a za stvarni projekat treba alat. Za Python je to coverage.py. On pokrene testove i za svaki red zapiše da li je izvršen. Instalacija i pokretanje iz foldera primjeri/pokrivenost:

pip install coverage
coverage run -m pytest test_dva.py
coverage report -m

Prva naredba pokreće pytest „pod nadzorom”, druga ispisuje izvještaj (-m znači: pokaži brojeve redova koji nedostaju). Za dva testa iz test_dva.py (N-1001 i N-1002) izvještaj je:

Name         Stmts   Miss  Cover   Missing
------------------------------------------
dostava.py      10      2    80%   7, 9
------------------------------------------
TOTAL           10      2    80%

6.8 Prvo mjerenje

Čitamo red po red: Stmts je broj iskaza (10), Miss broj neizvršenih (2), Cover procenat (80 %), a Missing tačno koji redovi nisu izvršeni: 7 i 9, dva raise. To se slaže s našim ručnim računom iz 6.4.

Dodajemo mjerenje grana opcijom --branch:

coverage run --branch -m pytest test_dva.py
coverage report -m
Name         Stmts   Miss Branch BrPart  Cover   Missing
--------------------------------------------------------
dostava.py      10      2      6      2    75%   7, 9
--------------------------------------------------------
TOTAL           10      2      6      2    75%

6.8 Prvo mjerenje

Nove kolone: Branch je broj ishoda odluka (6, kao u tabeli iz 6.5), a BrPart (partial) broj odluka kod kojih je izvršen samo jedan ishod (2: odluke u redovima 6 i 8 nikad nisu dale DA). Ukupno je 75 %.

Za čitljiviji prikaz postoji HTML izvještaj:

coverage html

Otvorite htmlcov/index.html u pregledniku i kliknite na dostava.py. Svaki red je obojen: zeleno izvršen, crveno nije izvršen, žuto odluka kod koje je izvršen samo jedan ishod. Pređite mišem preko žutog reda i alat napiše koja grana fali, npr. „line 6 didn't jump to line 7”. To je mapa grada s obojenim ulicama iz 6.1.

6.8 Prvo mjerenje

Za radoznale

Mnogi projekti koriste dodatak pytest-cov, koji isto radi jednom naredbom: pytest --cov=. --cov-branch --cov-report=term-missing. Rezultat je isti, jer pytest-cov iznutra koristi coverage.py.

Ukratko – 6.8 Prvo mjerenje

  • coverage.py pokreće testove naredbom coverage run -m pytest i bilježi izvršene redove.
  • coverage report -m ispisuje procenat i brojeve redova koji nisu izvršeni.
  • Opcija --branch dodaje pokrivenost grana; kolona BrPart broji odluke s izvršenim samo jednim ishodom.
  • coverage html pravi izvještaj u kojem su redovi obojeni zeleno, crveno i žuto.

6.9 Od 62 % do 100 %

Kolona Missing nije ocjena, nego spisak zadataka: svaki broj u njoj je test koji fali. Pratimo kako pokrivenost raste dok dodajemo testove (slika 6.4).

Korak 1 – samo N-1001. Pokrivenost grana je 62 %, a nedostaju redovi 7, 9, 11. Treba nam narudžba sa besplatnom dostavom (red 11), nešto izvan zone (red 7) i nešto ispod minimuma (red 9).

Korak 2 – dodajemo N-1002. Red 11 je izvršen; pokrivenost je 75 %, nedostaju 7 i 9.

Korak 3 – dodajemo tri testa izuzetaka iz test_svi.py:

6.9 Od 62 % do 100 %

def test_negativna_udaljenost():
    with pytest.raises(ValueError):
        cijena_dostave(-1, 1000)


def test_izvan_zone():
    with pytest.raises(ValueError):
        cijena_dostave(11, 1000)


def test_ispod_minimuma():
    with pytest.raises(ValueError):
        cijena_dostave(5, 450)

6.9 Od 62 % do 100 %

coverage run --branch -m pytest test_svi.py
coverage report -m
Name         Stmts   Miss Branch BrPart  Cover
----------------------------------------------
dostava.py      10      0      6      0   100%
----------------------------------------------
TOTAL           10      0      6      0   100%

Pet testova, 100 % iskaza i grana. Kolona Missing je prazna.

Slika 6.4 – Pokrivenost iskaza i grana dok se dodaju testovi: 1, 2 i 5 testova
Slika 6.4 – Pokrivenost iskaza i grana dok se dodaju testovi: 1, 2 i 5 testova

6.9 Od 62 % do 100 %

Primijetite da je test s 11 km tu zbog MC/DC, a ne zbog grana: grane bi bile 100 % i bez njega, jer −1 km već daje DA u prvoj odluci. Bez tog testa bismo imali 100 % grana, a greška > 100 umjesto > 10 bi prošla neopaženo.

Isto mjerenje nad testovima DeliveryApp (primjeri/deliveryapp, coverage run --branch -m pytest tests) daje 98 % za deliveryapp.py. (U folderu su već i testovi iz poglavlja 8; samo s testovima iz poglavlja 4 i 5 rezultat je isti.) Jedini neizvršen red je funkcija eur, koja samo formatira iznos za ekran: za nju još niko nije napisao test.

Na času

U HTML izvještaju jedna linija je žuta: if iznos >= 3000: s porukom „line 10 didn't jump to line 11”. Kakav test treba dopisati? – Test u kojem je iznos 30,00 € ili više, npr. N-1002, očekivano 0,00 € dostave.

Ukratko – 6.9 Od 62 % do 100 %

  • Svaki broj u koloni Missing je zadatak: test koji treba dopisati.
  • Za cijena_dostave pokrivenost grana raste s 62 % (1 test) na 75 % (2 testa) i 100 % (5 testova).
  • Test s 11 km ne povećava pokrivenost grana, ali ga traži MC/DC.
  • Testovi DeliveryApp iz poglavlja 4 i 5 pokrivaju 98 % fajla deliveryapp.py.

6.10 Zašto 100 % nije kraj

Imamo 100 % iskaza i grana. Da li to znači da je cijena_dostave bez grešaka? Napravimo eksperiment. U dostava.py promijenite jedan znak, kao u grešci D-01 iz prve verzije DeliveryApp:

    if iznos > 3000:      # bilo je >= 3000
        return 0

Sada narudžba od tačno 30,00 € plaća dostavu, što krši PP-4. Pokrenimo isti skup testova:

coverage run --branch -m pytest test_svi.py
.....                                                                    [100%]
5 passed in 0.01s

6.10 Zašto 100 % nije kraj

Name         Stmts   Miss Branch BrPart  Cover
----------------------------------------------
dostava.py      10      0      6      0   100%

Pet prolaza i 100 % pokrivenosti, a kod je pogrešan. Zašto? Pokrivenost mjeri da li je red izvršen, a ne da li je provjeren pravom vrijednošću. Naš test za besplatnu dostavu koristi 32,00 €, a za 32,00 € su i >= i > tačni. Nijedan test ne stoji na granici.

Grešku hvata test iz test_granica.py, napravljen iz pravila, a ne iz koda:

def test_tacno_30_eura_besplatno():
    assert cijena_dostave(5, 3000) == 0


def test_29_99_placa_dostavu():
    assert cijena_dostave(5, 2999) == 300

6.10 Zašto 100 % nije kraj

FAILED test_granica.py::test_tacno_30_eura_besplatno - assert 300 == 0
1 failed, 6 passed in 0.04s

Za tačno 30,00 € pogrešan kod vraća 300 centi (3,00 € za 5 km), a pravilo kaže 0. Ovakve testove pravi analiza graničnih vrijednosti, tehnika crne kutije iz poglavlja 8. A ideja „namjerno pokvari kod i vidi da li testovi to primijete” zove se testiranje mutacijama i učimo je u poglavlju 7.

Tri pouke za pamćenje:

  1. Pokrivenost pokazuje šta NIJE testirano, i tu je vrlo korisna. Crveni red je sigurno netestiran.
  2. Pokrivenost ne pokazuje da je nešto DOBRO testirano. Zeleni red je izvršen, ali možda bez provjere (test bez assert također podiže pokrivenost!) ili s pogrešnim podacima.
  3. Kad pokrivenost postane cilj, prestaje biti dobra mjera. Tim kojem šef kaže „mora biti 100 %” brzo nauči pisati testove koji izvršavaju kod, ali ništa ne provjeravaju.

6.10 Zašto 100 % nije kraj

Zato se u praksi postavlja razuman prag, a ne 100 %. coverage.py ga može provjeriti sam:

coverage report --fail-under=80

Ako je pokrivenost ispod 80 %, naredba završava greškom (za test_dva.py: „Coverage failure: total of 75 is less than fail-under=80”). U poglavlju 14 tu naredbu stavljamo u GitHub Actions, pa svaki push koji spusti pokrivenost ispod praga dobije crveni znak.

Česta zabluda

„Imamo 100 % pokrivenosti, dakle nemamo grešaka.” Ne: imamo dokaz da je svaki red izvršen, ne da je svaki red tačan. D-01 je preživio 100 % pokrivenosti.

Ukratko – 6.10 Zašto 100 % nije kraj

  • Pokrivenost mjeri da li je kod izvršen, a ne da li je rezultat provjeren pravom vrijednošću.
  • Greška D-01 (> umjesto >=) preživi 100 % pokrivenosti, a uhvati je test s tačno 30,00 €.
  • Pokrivenost je odlična za nalaženje netestiranog koda, a slaba kao dokaz kvaliteta testova.
  • U praksi se postavlja razuman prag, npr. --fail-under=80, a ne slijepa trka za 100 %.

Provjeri se

  1. Šta znači kolona Missing u izvještaju coverage report -m? Brojevi redova koje nijedan test nije izvršio.
  2. Da li test bez assert povećava pokrivenost? Da: kod je izvršen, iako ništa nije provjereno.
  3. Koji test hvata D-01 kad 100 % pokrivenosti ne hvata? Test na granici: tačno 30,00 € mora dati besplatnu dostavu.

Odgovori: tipka R ili klik na zamućeno polje.

Praksa · Sedmica 6

Praktična nastava – Mjerimo pokrivenost DeliveryApp

Praktična nastava – Mjerimo pokrivenost DeliveryApp

Cilj je izmjeriti pokrivenost koda DeliveryApp, pročitati izvještaj, dopisati testove dok pokrivenost grana ne bude 100 % i pokazati da 100 % ne hvata sve greške. Radi se u parovima.

Korak 1 – Graf i bazni putevi rukom (30 minuta)

  1. Nacrtajte na papiru graf toka kontrole funkcije napojnica(iznos, procenat) iz primjeri/deliveryapp/napojnica.py iz poglavlja 5.
  2. Izračunajte V(G) na dva načina (E − N + 2 i broj odluka + 1).
  3. Napišite tabelu baznih puteva: put, ulaz, očekivani rezultat, pravilo (PP-8). Očekivani rezultat računajte iz pravila, ne iz koda.

Korak 2 – Od 62 % do 100 % (45 minuta)

  1. U folderu primjeri/pokrivenost instalirajte coverage (pip install coverage) i pokrenite coverage run --branch -m pytest test_dva.py i coverage report -m. Zapišite brojeve.
  2. Napravite svoj fajl test_moji.py koji počinje samo s testom N-1001. Izmjerite (očekivano 62 %).
  3. Dodajte po jedan test, svaki put izmjerite i zapišite tabelu: test, pokrivenost iskaza, pokrivenost grana, redovi u Missing.
  4. Otvorite coverage html i napravite snimak ekrana prije i poslije (crveni, žuti i zeleni redovi).

Korak 3 – Pokrivenost cijelog DeliveryApp (30 minuta)

  1. U folderu primjeri/deliveryapp pokrenite coverage run --branch -m pytest tests i coverage report -m --include="deliveryapp.py,napojnica.py".
  2. Koji red nije pokriven? Dopišite test za funkciju eur (npr. 2450 → „24,50 €”, 5 → „0,05 €”) i dovedite deliveryapp.py do 100 %.
  3. Pokrenite isto mjerenje sa DeliveryApp=v0 (u PowerShellu $env:DeliveryApp="v0") i coverage report -m bez opcije --include. Pokrivenost se mjeri i kad testovi padaju: 10 testova pada, a deliveryapp_v0.py je ipak pokriven 98 %. Zapišite šta to govori o odnosu „pokrivenost” i „prolaz”.

Korak 4 – Mutant koji preživi 100 % (30 minuta)

  1. Dok test_svi.py daje 100 %, u dostava.py promijenite >= u >. Pokrenite testove: šta se desi s pokrivenošću i s prolazima?
  2. Napravite još tri male izmjene, jednu po jednu: udaljenost_km > 10 u > 100; 200 + 50 u 200 + 60; math.ceil(max(0, udaljenost_km - 3)) u math.ceil(udaljenost_km - 3) (bez max). Za svaku zapišite: da li test_svi.py pada? (Savjet za treću: koliko je math.ceil(1 - 3)?)
  3. Za svaku izmjenu koja preživi napišite test koji je hvata (kao test_granica.py). Na kraju vratite originalni kod i provjerite da svi testovi prolaze.

Korak 5 – Prag pokrivenosti (15 minuta)

  1. Pokrenite coverage report --fail-under=80 sa test_dva.py i sa test_svi.py. Zapišite poruke i kod izlaza (u PowerShellu $LASTEXITCODE).
  2. Raspravite u paru: koji prag biste postavili za DeliveryApp i zašto ne 100 %?

Korak 6 – AI i pokrivenost (opcionalno)

Dajte AI asistentu funkciju cijena_dostave (bez testova) i zatražite „testove za 100 % pokrivenosti grana”. Pokrenite ih sa --branch. Da li su 100 %? Da li bi uhvatili > umjesto >=? Zapišite koliko testova ima očekivani rezultat izračunat iz pravila, a koliko je samo prepisalo ono što kod vrati.

Rezultat koji se predaje: fajl rezultati-6.md s grafom funkcije napojnica (slika ili Mermaid), V(G) i tabelom baznih puteva; tabela rasta pokrivenosti iz koraka 2 sa snimcima HTML izvještaja; test za eur i izvještaj sa 100 %; tabela mutanata iz koraka 4 s testovima koji ih hvataju; odgovor o pragu iz koraka 5.

Vježbe

Vježbe za studenta

Rješenja su sakrivena – tipka R ili klik na okvir.

Vježba za studenta 1 – graf i V(G).

Zadatak

Nacrtajte graf toka kontrole i izračunajte V(G) za funkciju:

def moze_otkazati(stanje):
    if stanje == "NOVA":
        return True
    if stanje == "PRIHVAĆENA":
        return True
    return False

Vježba za studenta 1 – graf i V(G). – rješenje

Rješenje (R)

Čvorovi: odluka 1 (stanje == "NOVA"), return True (2), odluka 3, return True (4), return False (5), kraj (6): 6 čvorova. Grane: 1→2, 1→3, 3→4, 3→5, 2→kraj, 4→kraj, 5→kraj: 7 grana. V(G) = 7 − 6 + 2 = 3 = 2 odluke + 1. Bazni putevi: „NOVA” → True; „PRIHVAĆENA” → True; „U_PRIPREMI” → False (PP-6).

Vježba za studenta 2 – iskazi i grane.

Zadatak

Za funkciju dostava_s_kodom iz 6.5 imamo jedan test: dostava_s_kodom(300, "BESPLATNO") == 0. Kolika je pokrivenost iskaza, a kolika grana? Koji test dodati?

Vježba za studenta 2 – iskazi i grane. – rješenje

Rješenje (R)

Iskazi: 100 % (sva četiri). Grane: odluka je dala samo DA, pa je pokrivena 1 od 2 grane. coverage.py ispiše 83 % uz napomenu 5->7: grana iz reda 5 direktno u red 7 (ishod NE) nikad nije izvršena. Dodati test dostava_s_kodom(300, "") == 300 (ili s bilo kojim drugim kodom): bez koda cijena ostaje 3,00 €.

Vježba za studenta 3 – MC/DC.

Zadatak

Odluka glasi if iznos >= 3000 and kod_ok: (besplatna dostava samo s važećim kodom). Napravite najmanji skup testova za MC/DC.

Vježba za studenta 3 – MC/DC. – rješenje

Rješenje (R)

Za A and B tri testa: (da, da) → DA; (ne, da) → NE (pokazuje A); (da, ne) → NE (pokazuje B). Npr. 32,00 € i važeći kod → besplatno; 29,99 € i važeći kod → plaća; 32,00 € i nevažeći kod → plaća. Primijetite: za and polazni test je „oba tačna”, a za or (6.6) „oba lažna”.

Vježba za studenta 4 – čitanje izvještaja.

Zadatak

Izvještaj glasi:

Name         Stmts   Miss Branch BrPart  Cover   Missing
--------------------------------------------------------
dostava.py      10      3      6      3    62%   7, 9, 11

Šta testovi rade, a šta ne? Koja tri testa dopisati?

Vježba za studenta 4 – čitanje izvještaja. – rješenje

Rješenje (R)

Izvršena je samo plaćena dostava (sve tri odluke daju NE); to je jedan test kao N-1001. Fale: red 7 (izvan zone, npr. −1 km), red 9 (ispod minimuma, npr. 4,50 €) i red 11 (besplatna dostava, npr. 32,00 €). Uz test 11 km zbog MC/DC dobijamo test_svi.py.

Vježba za studenta 5 – 100 % i greška.

Zadatak

Kolega kaže: „Funkcija popust ima 100 % pokrivenosti grana, ne treba joj više testova.” Navedite grešku koja bi mogla proći.

Vježba za studenta 5 – 100 % i greška. – rješenje

Rješenje (R)

Npr. MAX_POPUST = 800 umjesto 500 (greška slična D-05): ako nijedan test nema iznos veći od 50,00 €, min uvijek vrati izračunati popust i pokrivenost ostaje 100 %, a greška prolazi. Treba test granice: 80,00 € sa STUDENT10 → 5,00 €. Druga mogućnost: kod malim slovima „student10” (D-03) – grana je ista, ali ulaz drugačiji.

Sažetak u pet rečenica

  1. Greška goto fail iz 2014. bila je jedan ponovljen red koji je preskakao provjeru potpisa, a mjerenje pokrivenosti bi pokazalo da se ti redovi nikad ne izvrše.
  2. Bijela kutija pravi i ocjenjuje testove gledajući kod, crta ga kao graf toka kontrole i broji nezavisne puteve ciklomatskom složenošću V(G) = broj odluka + 1, što je za cijena_dostave 4.
  3. Kriteriji pokrivenosti idu od slabijeg ka jačem: iskazi, grane, MC/DC i višestruki uslovi, a pokrivenost putanja je zbog petlji uglavnom teorijski ideal.
  4. Alat coverage.py mjeri pokrivenost naredbama coverage run --branch -m pytest i coverage report -m, a kolona Missing je spisak testova koje treba dopisati, od 62 % do 100 %.
  5. Pokrivenost pokazuje šta nije testirano, ali ne i da je testirano dobro: greška D-01 preživljava 100 % pokrivenosti, a hvata je tek test na granici od 30,00 €.

Pitanja za ponavljanje

  1. Šta je bila greška goto fail i kako bi je otkrilo mjerenje pokrivenosti?
  2. Koja je razlika između testiranja crnom i bijelom kutijom? Šta bijela kutija ne može naći?
  3. Šta su čvorovi i grane u grafu toka kontrole? Koliko ih ima graf funkcije cijena_dostave?
  4. Navedite dva načina računanja ciklomatske složenosti i izračunajte je za cijena_dostave.
  5. Šta su bazni putevi? Navedite bazne puteve funkcije cijena_dostave s ulazima i očekivanim rezultatima.
  6. Zašto je funkcija s V(G) većom od 10 problem?
  7. Šta je pokrivenost iskaza i kolika je za test N-1001?
  8. Pokažite primjerom da 100 % pokrivenosti iskaza ne znači 100 % pokrivenosti grana.
  9. Koja je razlika između odluke i uslova?
  10. Šta traži MC/DC? Napravite testove za odluku km < 0 or km > 10.
  11. Zašto se pokrivenost putanja rijetko koristi u praksi?
  12. Kojim naredbama se mjeri pokrivenost grana u coverage.py i šta znače kolone Branch, BrPart i Missing?
  13. Zašto 100 % pokrivenosti ne garantuje kod bez grešaka? Navedite primjer iz DeliveryApp.
  14. Šta radi opcija --fail-under i zašto se prag obično ne postavlja na 100 %?