Testiranje softvera · Poglavlje 10 · Sedmica 10

Sistemsko i prihvatno testiranje

Dio 1 – Sistemsko testiranje

Dio 2 – Nefunkcionalno testiranje

Dio 3 – Prihvatno testiranje i BDD

Praksa – Sistem, opterećenje i prihvatanje

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 10 (Sedmica 10, 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 10

Priča za početak

Priča za početak

Prvog oktobra 2013. američka vlada otvorila je web stranicu Healthcare.gov, preko koje su milioni građana trebali izabrati i kupiti zdravstveno osiguranje. Bio je to jedan od najvažnijih i najskupljih projekata te vlade, i cijela zemlja je čekala. Stranica je pala skoro odmah. Ljudi su satima gledali poruke o grešci, prazne stranice i beskrajno učitavanje. Prema internim bilješkama objavljenim kasnije, prvog dana je kupovinu osiguranja uspjelo završiti svega šest ljudi, a drugog dana 248. Šta se desilo? Stranica je bila planirana za oko 60 000 istovremenih korisnika, a prvih dana ih je došlo oko 250 000.

Ali problem je bio dublji od pogrešne procjene. Nekoliko dana prije otvaranja urađen je test opterećenja, i stranica je pala već s nekoliko stotina istovremenih korisnika. Izvođači su kasnije pred Kongresom rekli da je za testiranje cijelog sistema trebalo nekoliko mjeseci, a dobili su oko dvije sedmice. Dijelove su pravile različite firme, i svaki dio je testiran zasebno, ali cijeli sistem, sa svim dijelovima zajedno i pod pravim opterećenjem, nije bio provjeren na vrijeme. I upozorenje koje je test dao nije zaustavilo otvaranje. Popravka je trajala mjesecima i uključila hitno okupljen tim inženjera iz velikih tehnoloških firmi. Healthcare.gov je postao školski primjer onoga što se dešava kad se sistemsko testiranje i testiranje performansi ostave za kraj, i kad se rezultati testa ne poslušaju.

Slika 10.1 – Healthcare.gov 2013: test je pokazao pad s nekoliko stotina korisnika, a došlo ih je stotine hiljada
Slika 10.1 – Healthcare.gov 2013: test je pokazao pad s nekoliko stotina korisnika, a došlo ih je stotine hiljada

Zašto ovo poglavlje

U poglavlju 9 spojili smo dijelove DeliveryApp: pravila, servise mapa i plaćanja, API. Ovo poglavlje se penje na vrh V-modela iz poglavlja 2. Prvo sistemsko testiranje: cijeli DeliveryApp, na pravom serveru, preko prave mreže, kao što ga koristi kupac. Zatim nefunkcionalno testiranje: ne pitamo „da li radi”, nego „koliko brzo, za koliko korisnika, koliko sigurno i koliko lako”. Na kraju prihvatno testiranje: da li sistem radi ono što kupac i vlasnik proizvoda zaista žele, napisano jezikom koji razumiju svi, u stilu BDD.

Riječi ovog poglavlja (1/2)

  • Sistemsko testiranje – testiranje cijelog, sklopljenog sistema u okruženju što sličnijem stvarnom.
  • Funkcionalno i nefunkcionalno – funkcionalno pita šta sistem radi (cijena, stanje); nefunkcionalno pita kako to radi (brzina, sigurnost, upotrebljivost).
  • Okruženje – računari, baze i podešavanja na kojima sistem radi: razvojno, testno, predprodukcijsko (staging), produkcijsko.
  • Vrijeme odziva – koliko korisnik čeka od zahtjeva do odgovora.
  • Percentil – vrijednost ispod koje je dati procenat mjerenja; „95. percentil je 16 ms” znači da je 95 % zahtjeva završilo za najviše 16 ms.
  • Propusnost (throughput) – broj zahtjeva koje sistem obradi u sekundi.

Riječi ovog poglavlja (2/2)

  • Test opterećenja, stresa, skoka i izdržljivosti – testovi performansi s očekivanim, rastućim, naglim i dugotrajnim brojem korisnika.
  • OWASP Top 10 – spisak deset najčešćih kategorija sigurnosnih propusta u web aplikacijama.
  • Prihvatno testiranje (acceptance testing, UAT) – testiranje koje odlučuje da li korisnik ili naručilac prihvata sistem.
  • Kriterij prihvatanja – konkretan, provjerljiv uslov koji korisnička priča mora ispuniti da bi bila „gotova”.
  • BDD (Behavior-Driven Development) – razvoj vođen ponašanjem: zahtjevi se pišu kao primjeri ponašanja, jezikom koji razumiju i korisnik i programer, i ti primjeri postaju automatski testovi.
  • Gherkin – jezik za BDD scenarije s ključnim riječima Dato, Kada, Zatim (na engleskom Given, When, Then).

Ciljevi poglavlja

Nakon poglavlja možete:

objasniti šta je sistemsko testiranje i po čemu se razlikuje od integracionog; nabrojati okruženja i reći zašto test mora ličiti na produkciju; napisati sistemski test koji pokreće pravi server i prolazi cijeli put narudžbe; razlikovati vrste testova performansi; napisati scenarij za Locust i pročitati percentile; prepoznati osnovne sigurnosne propuste iz OWASP Top 10 na primjeru DeliveryApp; objasniti vrste prihvatnog testiranja; napisati kriterije prihvatanja i BDD scenarij na bosanskom jeziku i pokrenuti ga alatom pytest-bdd.

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

ČasSadržajNa času
Teorija 110.1–10.3 Sistemsko testiranje; okruženja; put narudžbe od kraja do krajaŠta sve mora raditi da bi N-1001 stigla kupcu?
Teorija 210.4–10.6 Performanse i Locust; sigurnost; upotrebljivost200 korisnika na DeliveryApp
Teorija 310.7–10.9 Prihvatno testiranje; kriteriji prihvatanja; BDD i GherkinScenarij „Dato – Kada – Zatim”
Dio 1 · Sedmica 10

Dio 1 – Sistemsko testiranje

10.1 Cijeli sistem, kao kupac

Sistemsko testiranje provjerava sklopljen sistem u cjelini, u okruženju što sličnijem onom u kojem će ga koristiti ljudi. Na V-modelu (poglavlje 2) ono stoji naspram specifikacije sistema: jedinični testovi provjeravaju dizajn funkcija, integracioni saradnju dijelova, a sistemski da li cijeli sistem ispunjava zahtjeve.

Razlika u odnosu na integraciju iz poglavlja 9:

10.1 Cijeli sistem, kao kupac

IntegracionoSistemsko
Šta se testirasaradnja dva ili više dijelovacijeli sistem
Ko obično testiraprogramerinezavisni testni tim
Spoljni servisičesto dvojnicipravi ili vjerne kopije
Okruženjeračunar programeratestno okruženje slično produkciji
Zahtjevifunkcionalni (šta)funkcionalni i nefunkcionalni (šta i kako)

Slika iz života: tehnički pregled auta. Mehaničar je ranije provjerio kočnice i motor odvojeno (jedinični testovi) i kako rade zajedno (integracija). Na tehničkom pregledu se auto provjerava cijeli, onakav kakav izlazi na cestu: svjetla, kočnice, izduvni gasovi, sve odjednom, po propisanoj listi.

Sistemsko testiranje je skoro uvijek crna kutija: tester gleda sistem spolja, kao korisnik, i koristi tehnike iz poglavlja 8 (klase, granice, tabele, stanja) nad cijelim sistemom.

Ukratko – 10.1 Cijeli sistem, kao kupac

  • Sistemsko testiranje provjerava sklopljen sistem u cjelini, u okruženju sličnom stvarnom.
  • Na V-modelu stoji naspram specifikacije sistema i provjerava funkcionalne i nefunkcionalne zahtjeve.
  • Obično ga radi nezavisan testni tim, tehnikama crne kutije.
  • Za razliku od integracije, koristi prave ili vjerne kopije spoljnih servisa.

10.2 Okruženja

Program koji radi „na mom računaru” ne mora raditi na serveru. Zato sistemi obično imaju nekoliko okruženja:

10.2 Okruženja

OkruženjeZa štaPodaci
razvojno (development)programer piše i probava kodizmišljeni, mali
testno (test, QA)testeri testiraju novu verzijutestni skup (N-1001, K-01…)
predprodukcijsko (staging)posljednja proba, što sličnije produkcijikopija strukture produkcije, bez stvarnih ličnih podataka
produkcijsko (production)stvarni korisnicistvarni

Sistemski test ima smisla samo ako okruženje liči na produkciju: ista verzija Pythona, ista baza, ista podešavanja, slična količina podataka. Healthcare.gov je dobar primjer suprotnog: dijelovi su testirani u svojim okruženjima, a cijeli sistem skoro nikako.

Dvije zamke:

  1. Razlike u okruženju. Test prolazi na testnom serveru s 10 narudžbi u bazi, a produkcija s 10 miliona je spora. Ili test koristi drugi format datuma od produkcije.
  2. Stvarni podaci u testu. Kopirati produkcijsku bazu s imenima, adresama i karticama kupaca na testni server je zabranjeno zakonima o zaštiti podataka (GDPR u EU, zakon o zaštiti ličnih podataka u BiH) i opasno. Testni podaci se izmišljaju ili se stvarni podaci anonimizuju. Ista zabrana važi za AI razgovore: stvarni podaci kupaca ne idu u AI alat.

Ukratko – 10.2 Okruženja

  • Sistem prolazi kroz razvojno, testno, predprodukcijsko i produkcijsko okruženje.
  • Sistemski test ima smisla samo u okruženju koje liči na produkciju.
  • Razlike u okruženju (verzije, količina podataka, podešavanja) česte su uzrok grešaka koje se vide tek u produkciji.
  • Stvarni lični podaci ne smiju u testno okruženje ni u AI alat; koriste se izmišljeni ili anonimizovani.

10.3 Put narudžbe od kraja do kraja

Šta sve mora raditi da bi N-1001 stigla kupcu? Server mora biti pokrenut, mreža mora raditi, API mora primiti JSON, pravila moraju izračunati 24,50 €, narudžba mora proći pet stanja, i kupac mora vidjeti istoriju. Sistemski test sve to provjerava jednim tokom, kao pravi korisnik.

Fajl primjeri/deliveryapp/tests_sistem/test_sistem.py za to pokrene pravi server (uvicorn api:app) kao poseban proces i šalje mu HTTP zahtjeve preko mreže, običnom bibliotekom urllib, kao što bi to radio bilo koji klijent:

10.3 Put narudžbe od kraja do kraja

@pytest.fixture(scope="module")
def server():
    """Pokrene server, sačeka da odgovori, a na kraju ga ugasi."""
    proces = subprocess.Popen([sys.executable, "-m", "uvicorn", "api:app", "--port", "8765"], cwd=FOLDER)
    ...                                      # čeka dok server ne odgovori
    yield ADRESA
    proces.terminate()


def test_put_narudzbe_od_pocetka_do_kraja(server):
    # 1. kupac pogleda jelovnik Picerije
    status, jela = zahtjev("GET", "/v1/jela?restoran=R-1")
    assert status == 200 and len(jela) == 3

    # 2. naruči N-1001: 21,50 € + 3,00 € dostave
    status, n = zahtjev("POST", "/v1/narudzbe", N1001)
    assert status == 201
    assert (n["stanje"], n["ukupno"]) == ("NOVA", 2450)
    broj = n["broj"]

    # 3. restoran, kuhinja i dostavljač vode narudžbu do kupca
    for stanje in ["PRIHVAĆENA", "U_PRIPREMI", "NA_PUTU", "ISPORUČENA"]:
        status, _ = zahtjev("PATCH", f"/v1/narudzbe/{broj}/stanje", {"stanje": stanje})
        assert status == 200, stanje

    # 4. kupac vidi cijelu istoriju
    status, n = zahtjev("GET", f"/v1/narudzbe/{broj}")
    assert n["istorija"] == ["NOVA", "PRIHVAĆENA", "U_PRIPREMI", "NA_PUTU", "ISPORUČENA"]

10.3 Put narudžbe od kraja do kraja

Fixture ima scope="module": server se pokrene jednom za sve testove u fajlu, a ne za svaki test posebno, jer pokretanje traje.

pytest -q tests_sistem
...                                                                      [100%]
3 passed in 0.92s

Nad prvom verzijom (DeliveryApp=v0) padaju put narudžbe (ukupno 24,00 € umjesto 24,50 €, D-02) i otkazivanje u pripremi (200 umjesto 409, D-04):

FAILED tests_sistem/test_sistem.py::test_put_narudzbe_od_pocetka_do_kraja - A...
FAILED tests_sistem/test_sistem.py::test_otkazivanje_u_pripremi_odbijeno - as...
2 failed, 1 passed in 0.70s

10.3 Put narudžbe od kraja do kraja

Isti nalazi kao kroz TestClient u poglavlju 9? Da, i to je dobro: sistemski test ne treba da nalazi nove greške u pravilima, njih su našli niži nivoi. Njegov posao je da nađe ono što niži nivoi ne vide: server se ne pokreće, port je zauzet, JSON se pogrešno kodira preko mreže, slova Ć i Ž se pokvare, nedostaje biblioteka na serveru. Zato je sistemskih testova malo (vrh piramide iz poglavlja 4), ali moraju postojati.

Na času

Šta bi sistemski test otkrio, a TestClient test ne bi? Navedite tri primjera. – Na primjer: server ne može da se pokrene jer nedostaje uvicorn; port 8000 je zauzet drugim programom; pogrešno podešen zapis znakova pa „PRIHVAĆENA” stiže kao „PRIHVAĆENA”; zaštitni zid (firewall) blokira zahtjeve.

Ukratko – 10.3 Put narudžbe od kraja do kraja

  • Sistemski test prolazi cijeli put korisnika jednim tokom: jelovnik, narudžba, sva stanja, istorija.
  • Test u DeliveryApp pokreće pravi server kao poseban proces i šalje zahtjeve preko mreže.
  • Fixture s scope="module" pokreće server jednom za sve testove u fajlu.
  • Sistemskih testova je malo, a hvataju ono što niži nivoi ne vide: pokretanje, mrežu, kodiranje, okruženje.

Provjeri se

  1. Po čemu se sistemsko testiranje razlikuje od integracionog? Testira cijeli sistem u okruženju sličnom produkciji, s pravim servisima, i provjerava i nefunkcionalne zahtjeve.
  2. Smiju li se u testnom okruženju koristiti stvarni podaci kupaca? Ne, samo izmišljeni ili anonimizovani.
  3. Zašto fixture servera ima scope="module"? Da se server pokrene jednom za sve testove u fajlu, jer pokretanje traje.

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

Dio 2 · Sedmica 10

Dio 2 – Nefunkcionalno testiranje

10.4 Performanse i Locust

Funkcionalni test pita: „Da li je cijena N-1001 24,50 €?” Test performansi pita: „Da li je cijena N-1001 24,50 € i kad u isto vrijeme pita još 199 ljudi, i koliko dugo svako čeka?”

Za DeliveryApp imamo nefunkcionalni zahtjev:

NZ-1. Pri 200 istovremenih korisnika, 95 % zahtjeva mora završiti za najviše 2 sekunde, bez grešaka.

Primijetite oblik zahtjeva: ima broj korisnika, procenat i granicu vremena. Zahtjev „stranica mora biti brza” ne može se testirati; NZ-1 može.

Postoje četiri glavne vrste testova performansi (slika 10.2):

Slika 10.2 – Četiri vrste testova performansi: broj korisnika kroz vrijeme
Slika 10.2 – Četiri vrste testova performansi: broj korisnika kroz vrijeme

10.4 Performanse i Locust

VrstaPitanjeDeliveryApp
opterećenje (load)radi li sistem pri očekivanom broju korisnika?200 korisnika, NZ-1
stres (stress)gdje je granica i šta se desi kad je pređemo?povećavati dok ne padne
skok (spike)podnosi li nagli skok?petak u 19 h, reklama na TV-u
izdržljivost (soak, endurance)radi li satima i danima bez kvarenja?150 korisnika 8 sati; traži „curenje” memorije

Za mjerenje treba alat koji glumi stotine korisnika. Locust je takav alat za Python: korisnik se opisuje kao klasa, a Locust pokrene koliko god kopija treba. Fajl primjeri/deliveryapp/locustfile.py:

10.4 Performanse i Locust

class Kupac(HttpUser):
    """Jedan virtuelni kupac: gleda jelovnik, provjerava cijenu i ponekad naruči."""

    wait_time = between(1, 3)        # kupac „razmišlja” 1 do 3 sekunde između klikova

    @task(5)
    def jelovnik(self):
        self.client.get("/v1/jela", params={"restoran": random.choice(["R-1", "R-2", "R-3"])})

    @task(3)
    def cijena(self):
        with self.client.post("/v1/cijena", json=N1001, catch_response=True) as r:
            if r.status_code != 200 or r.json().get("ukupno") != 2450:
                r.failure(f"pogrešna cijena: {r.status_code} {r.text[:80]}")

    @task(1)
    def narudzba(self):
        self.client.post("/v1/narudzbe", json=N1001)

10.4 Performanse i Locust

Brojevi u @task(5), @task(3), @task(1) su težine: od 9 radnji, prosječan kupac 5 puta pogleda jelovnik, 3 puta provjeri cijenu i jednom naruči, kao pravi kupci. Primijetite i da test performansi provjerava rezultat: cijena mora biti 24,50 €. Brz odgovor s pogrešnim iznosom nije uspjeh.

Pokretanje: u jednom terminalu server, u drugom Locust bez grafičkog prikaza (200 korisnika, 20 novih u sekundi, 30 sekundi):

uvicorn api:app --port 8000
locust -f locustfile.py --headless -u 200 -r 20 -t 30s --host http://127.0.0.1:8000

Skraćen rezultat jednog mjerenja na laptopu:

10.4 Performanse i Locust

Type     Name                    # reqs      # fails |    Avg     Min     Max    Med |   req/s
POST     /v1/cijena                 864     0(0.00%) |      4       0      37      3 |   29.44
POST     /v1/narudzbe               285     0(0.00%) |      4       0      36      3 |    9.71
         Aggregated                2584     0(0.00%) |      4       0      43      3 |   88.05

Response time percentiles (approximated)
Type     Name                      50%    66%    75%    80%    90%    95%    98%    99%   100%
         Aggregated                  3      4      5      6      8     16     18     22     44
Slika 10.3 – Percentili vremena odziva: 95 % zahtjeva završilo je za najviše 16 ms
Slika 10.3 – Percentili vremena odziva: 95 % zahtjeva završilo je za najviše 16 ms

10.4 Performanse i Locust

Kako čitati:

  • 2584 zahtjeva, 0 grešaka, oko 88 zahtjeva u sekundi (propusnost);
  • medijan 3 ms: pola zahtjeva završi za 3 ms ili brže;
  • 95. percentil 16 ms: to je broj iz NZ-1, i daleko je ispod 2000 ms; zahtjev je ispunjen;
  • najsporiji zahtjev 44 ms.

Zašto percentil, a ne prosjek? Prosjek sakriva loše slučajeve. Ako 95 kupaca čeka 0,1 s, a 5 čeka 30 s, prosjek je oko 1,6 s i „izgleda dobro”, a pet ljudi je zatvorilo aplikaciju. 95. percentil bi pokazao 30 s.

Česta zabluda

„Naš API odgovara za 16 ms, dakle DeliveryApp podnosi 200 korisnika.” Ovaj API čuva podatke u memoriji, nema bazu, nema pravi servis mapa ni banku, i radi na istom laptopu kao Locust. U stvarnom sistemu svaki od tih dijelova dodaje vrijeme, i baš oni obično prvi „pucaju”. Rezultat testa performansi važi samo za okruženje u kojem je izmjeren. Zato se ozbiljni testovi performansi rade u predprodukciji, na kopiji pravog sistema.

Ukratko – 10.4 Performanse i Locust

  • Test performansi provjerava brzinu i ispravnost pri mnogo istovremenih korisnika, prema mjerljivom zahtjevu kao NZ-1.
  • Vrste su opterećenje, stres, skok i izdržljivost.
  • Locust opisuje korisnika kao klasu s težinskim radnjama i pokreće stotine kopija.
  • Percentil je bolji od prosjeka jer pokazuje koliko čekaju najsporiji korisnici; za DeliveryApp je 95. percentil 16 ms.
  • Rezultat važi samo za okruženje u kojem je izmjeren.

10.5 Sigurnost

Sigurnosno testiranje pita: šta može uraditi neko ko ne bi smio? Za web aplikacije postoji poznat spisak, OWASP Top 10, deset najčešćih kategorija propusta, koji se povremeno ažurira. Nekoliko kategorija na primjeru DeliveryApp:

10.5 Sigurnost

KategorijaPitanje za DeliveryAppStanje u našem API-ju
pokvarena kontrola pristupamože li kupac K-02 promijeniti narudžbu kupca K-01? Može li kupac sam proglasiti narudžbu isporučenom?da, može: API nema prijavu ni provjeru ko šalje zahtjev
ubacivanje (injection)šta ako polje kupac sadrži SQL ili HTML kod?nema baze ni HTML-a, ali polje se ne provjerava
nesiguran dizajnvjeruje li server cijeni koju šalje klijent?ne: server sam računa cijenu (dobro)
pogrešna podešavanjada li greška otkriva detalje servera?FastAPI ne vraća trag greške korisniku (dobro)
ranjive komponentekoriste li se biblioteke s poznatim ranjivostima?treba redovno provjeravati (pip-audit)

Prvi red je pravi nalaz: u našem API-ju svako može poslati PATCH /v1/narudzbe/N-1001/stanje sa "ISPORUČENA". Za učionicu je to u redu, ali za pravi sistem je to ozbiljan propust: treba prijava (ko si?) i ovlaštenje (smiješ li to?). Kupac smije samo otkazati, restoran prihvatiti i odbiti, dostavljač preuzeti i isporučiti.

Takav nalaz se zapisuje kao izvještaj o defektu (poglavlje 3), s ozbiljnošću „visoka” i koracima za ponavljanje. Sigurnosni test za njega bi izgledao ovako (kad prijava postoji): kupac K-02 pokuša promijeniti narudžbu kupca K-01, očekivano 403 Forbidden.

10.5 Sigurnost

Iz stvarnog svijeta

Heartbleed (poglavlje 7) je bio „ranjiva komponenta” za svaku firmu koja je koristila OpenSSL: tuđa greška u biblioteci postala je njihova. Zato timovi danas automatski provjeravaju biblioteke koje koriste, alatima kao pip-audit za Python ili Dependabot na GitHubu.

Ukratko – 10.5 Sigurnost

  • Sigurnosno testiranje pita šta može uraditi neko ko ne bi smio.
  • OWASP Top 10 je spisak najčešćih kategorija propusta u web aplikacijama.
  • API DeliveryApp ima pokvarenu kontrolu pristupa: svako može promijeniti stanje bilo koje narudžbe.
  • Server dobro radi što sam računa cijenu i ne otkriva detalje greške.

10.6 Upotrebljivost i pristupačnost

Sistem može biti tačan, brz i siguran, a da ga ljudi ne znaju koristiti. Upotrebljivost (usability) pita: može li prosječan kupac naručiti N-1001 bez pomoći, brzo i bez greške? Testira se tako što se stvarni ljudi posmatraju dok rade zadatak („naručite dvije Margarite i sok na adresu Lipa 12 s kodom za studente”), a mjeri se:

  • da li su uspjeli,
  • koliko je trajalo,
  • gdje su zastali ili pogriješili,
  • koliko su zadovoljni (kratka anketa).

Već pet korisnika obično pokaže najveće probleme. Primjer nalaza: korisnici ne vide polje za kod popusta jer je ispod dugmeta „Naruči”.

10.6 Upotrebljivost i pristupačnost

Pristupačnost (accessibility) pita: mogu li stranicu koristiti i ljudi sa slabijim vidom, slijepi (uz čitač ekrana), ljudi koji ne mogu koristiti miš? Pravila su u međunarodnom standardu WCAG. Primjeri: dugmad imaju tekstualni opis (u stranici DeliveryApp aria-label="Dodaj Pizza Margarita"), kontrast teksta je dovoljan, sve se može uraditi tastaturom. Pristupačnost djelimično provjeravaju automatski alati, a detaljnije je radimo u poglavlju 13.

Ukratko – 10.6 Upotrebljivost i pristupačnost

  • Upotrebljivost se testira posmatranjem stvarnih ljudi dok rade zadatak; već pet korisnika pokaže najveće probleme.
  • Mjeri se uspjeh, vrijeme, mjesta zastoja i zadovoljstvo.
  • Pristupačnost znači da stranicu mogu koristiti i ljudi s invaliditetom, po standardu WCAG.
  • Dio pristupačnosti provjeravaju automatski alati, što radimo u poglavlju 13.

Provjeri se

  1. Zašto je 95. percentil bolji od prosjeka? Prosjek sakriva najsporije korisnike, a percentil pokazuje koliko oni čekaju.
  2. Koja je razlika između testa opterećenja i testa stresa? Opterećenje provjerava očekivani broj korisnika; stres povećava broj dok sistem ne padne, da se nađe granica.
  3. Koji sigurnosni propust ima API DeliveryApp? Pokvarena kontrola pristupa: svako može promijeniti stanje bilo koje narudžbe.

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

Dio 3 · Sedmica 10

Dio 3 – Prihvatno testiranje i BDD

10.7 Prihvatno testiranje

Sistem je prošao sve testove tima. Da li je gotov? Ne dok ga ne prihvati onaj za koga je napravljen. Prihvatno testiranje je posljednji nivo V-modela, naspram korisničkih zahtjeva, i ne pita „da li radi po specifikaciji”, nego „da li je ovo ono što nam treba”.

Vrste prihvatnog testiranja:

10.7 Prihvatno testiranje

VrstaKo testiraPrimjer za DeliveryApp
korisničko (UAT)stvarni korisnici ili njihovi predstavnicivlasnici tri restorana probaju aplikaciju sedmicu dana
operativnoadministratori i podrškarezervne kopije, vraćanje poslije pada, nadzor servera
ugovornonaručilac prema ugovorugrad koji je naručio aplikaciju provjerava stavke ugovora
regulatornoprema zakonu ili standarduzaštita ličnih podataka, fiskalni računi
alfakorisnici, kod proizvođačastudenti EUBD-a naručuju u učionici
betakorisnici, u stvarnom svijetu100 kupaca koristi aplikaciju mjesec dana prije svih

Prihvatni testovi se ne pišu na kraju. Pišu se na početku, zajedno sa zahtjevima, kao kriteriji prihvatanja: konkretni, provjerljivi uslovi koje priča mora ispuniti. Korisnička priča za DeliveryApp:

10.7 Prihvatno testiranje

Priča. Kao kupac, želim unaprijed znati koliko plaćam dostavu, da bih mogao odlučiti koliko naručujem. Kriteriji prihvatanja. 1. Za korpu od 30,00 € ili više dostava je 0,00 €. 2. Za korpu od 29,99 € na 5 km dostava je 3,00 €. 3. Kod STUDENT10 ne ukida besplatnu dostavu: 32,00 € s kodom košta 28,80 €. 4. Cijena dostave se vidi prije dugmeta „Naruči”.

Prva tri kriterija su upravo testovi iz poglavlja 8. Četvrti je kriterij upotrebljivosti i provjerava se ručno ili testom web stranice (poglavlje 13). Kad kriteriji postoje prije koda, svi znaju šta znači „gotovo”.

Ukratko – 10.7 Prihvatno testiranje

  • Prihvatno testiranje odlučuje da li korisnik ili naručilac prihvata sistem.
  • Postoje korisničko, operativno, ugovorno, regulatorno, alfa i beta prihvatno testiranje.
  • Kriteriji prihvatanja su konkretni, provjerljivi uslovi koji se pišu zajedno s korisničkom pričom.
  • Kad kriteriji postoje prije koda, svi znaju šta znači da je priča gotova.

10.8 BDD: primjeri koje razumiju svi

Kriteriji prihvatanja su napisani običnim jezikom. Testovi su napisani u Pythonu. Između njih je jaz: vlasnik restorana ne čita Python, a programer može pogrešno prevesti rečenicu u kod. BDD (Behavior-Driven Development, razvoj vođen ponašanjem) zatvara taj jaz: kriteriji se pišu kao scenariji u strogo propisanom obliku, koji je i dalje običan jezik, ali ga alat može izvršiti kao test.

Jezik scenarija zove se Gherkin. Ima nekoliko ključnih riječi, a postoji i na bosanskom:

10.8 BDD: primjeri koje razumiju svi

EngleskiBosanskiZnačenje
FeatureKarakteristikašta opisujemo (korisnička priča)
ScenarioScenariojedan primjer ponašanja
GivenDatopočetno stanje (pripremi)
WhenKadaradnja korisnika (izvrši)
ThenZatimočekivani ishod (provjeri)
And, ButI, Alinastavak prethodnog koraka
Scenario Outline, ExamplesScenariju-obris, Primjerijedan scenarij za tabelu primjera

10.8 BDD: primjeri koje razumiju svi

Prepoznajete li obrazac? Dato – Kada – Zatim je isto što i pripremi – izvrši – provjeri iz poglavlja 5, samo napisano za ljude.

Fajl primjeri/deliveryapp/tests_bdd/features/dostava.feature:

10.8 BDD: primjeri koje razumiju svi

# language: bs
Karakteristika: Cijena dostave i otkazivanje
  Kao kupac DeliveryApp
  želim unaprijed znati koliko plaćam dostavu
  da bih mogao odlučiti koliko naručujem

  Scenario: Narudžba od tačno 30,00 € ima besplatnu dostavu
    Dato korpa od 30,00 €
    I adresa udaljena 5 km
    Kada kupac zatraži cijenu
    Zatim dostava je 0,00 €
    I ukupno za plaćanje je 30,00 €

  Scenario: Studentski popust ne ukida besplatnu dostavu
    Dato korpa od 32,00 €
    I adresa udaljena 2,5 km
    I kod popusta "student10"
    Kada kupac zatraži cijenu
    Zatim dostava je 0,00 €
    I ukupno za plaćanje je 28,80 €

  Scenariju-obris: Dostava zavisi od iznosa i udaljenosti
    Dato korpa od <iznos> €
    I adresa udaljena <km> km
    Kada kupac zatraži cijenu
    Zatim dostava je <dostava> €

    Primjeri:
      | iznos | km  | dostava |
      | 10,00 | 3   | 2,00    |
      | 10,00 | 3,1 | 2,50    |
      | 21,50 | 4,2 | 3,00    |
      | 29,99 | 5   | 3,00    |
      | 30,00 | 5   | 0,00    |

10.8 BDD: primjeri koje razumiju svi

Prvi red, # language: bs, kaže alatu da su ključne riječi na bosanskom. Ovaj fajl može pročitati, ispraviti i potpisati vlasnik restorana. Iznosi su napisani kako ih piše kupac, s decimalnim zarezom i znakom €.

Ukratko – 10.8 BDD: primjeri koje razumiju svi

  • BDD piše kriterije prihvatanja kao scenarije koje razumiju svi, a alat ih izvršava kao testove.
  • Jezik scenarija je Gherkin, s ključnim riječima Karakteristika, Scenario, Dato, Kada, Zatim, I.
  • Dato – Kada – Zatim je isti obrazac kao pripremi – izvrši – provjeri.
  • Scenariju-obris s tabelom Primjeri pravi jedan scenarij za svaki red tabele.

10.9 Koraci u Pythonu i pytest-bdd

Da bi scenarij postao test, svaki korak treba povezati s malom Python funkcijom. To radi biblioteka pytest-bdd (pip install pytest-bdd). Fajl tests_bdd/test_dostava_bdd.py:

10.9 Koraci u Pythonu i pytest-bdd

from pytest_bdd import given, parsers, scenarios, then, when

from deliveryapp import Narudzba, cijena_dostave, popust

scenarios("features/dostava.feature")


def centi(tekst):
    """'30,00' -> 3000 (iznos kako ga piše kupac -> centi)."""
    eura, _, c = tekst.strip().partition(",")
    return int(eura) * 100 + int(c or 0)


@given(parsers.parse("korpa od {iznos} €"))
def korpa(narudzba_podaci, iznos):
    narudzba_podaci["iznos"] = centi(iznos)


@when("kupac zatraži cijenu")
def zatrazi_cijenu(narudzba_podaci):
    d = narudzba_podaci
    d["dostava"] = cijena_dostave(d["km"], d["iznos"])
    d["ukupno"] = d["iznos"] - popust(d["iznos"], d["kod"]) + d["dostava"]


@then(parsers.parse("dostava je {iznos} €"))
def provjeri_dostavu(narudzba_podaci, iznos):
    assert narudzba_podaci["dostava"] == centi(iznos)

10.9 Koraci u Pythonu i pytest-bdd

Kako radi:

  • scenarios(...) pročita fajl i od svakog scenarija napravi pytest test;
  • @given(parsers.parse("korpa od {iznos} €")) kaže: korak koji počinje sa „Dato korpa od …” izvršava ova funkcija, a ono što piše na mjestu {iznos} stiže kao parametar;
  • funkcija centi pretvara iznos kako ga piše kupac (30,00) u cente (3000), jer pravila rade u centima (poglavlje 5).
pytest -v tests_bdd
tests_bdd/test_dostava_bdd.py::test_studentski_popust_ne_ukida_besplatnu_dostavu PASSED
tests_bdd/test_dostava_bdd.py::test_dostava_zavisi_od_iznosa_i_udaljenosti[10,00-3,1-2,50] PASSED
...
8 passed in 0.06s

Četiri scenarija daju 8 testova (obris s pet primjera daje pet). Nad prvom verzijom pada 6 od 8: tačno 30,00 € (D-01), kod malim slovima (D-03), 3,1 km i 4,2 km (D-02), 30,00 € u tabeli (D-01) i otkazivanje u pripremi (D-04). Dva prolaze: 3 km i 29,99 €, jer tu prva verzija slučajno računa tačno.

10.9 Koraci u Pythonu i pytest-bdd

Najveća vrijednost BDD-a nije u alatu, nego u razgovoru. Scenariji nastaju na sastanku na kojem sjede vlasnik proizvoda, programer i tester (tzv. „tri amigosa”) i zajedno smišljaju primjere: „A šta ako je korpa tačno 30,00 €? A ako s popustom padne ispod 30,00 €?” Svako pitanje koje se tu postavi je greška koja se neće napisati.

Česta zabluda

„BDD znači pisati sve testove u Gherkinu.” Ne. Gherkin je za ponašanje važno korisniku, desetine scenarija, a ne stotine. Granice od 0,01 km, 49 prelaza stanja i 200 nizova modela ostaju u običnim pytest testovima, gdje su kraći i brži. Ako vlasnik proizvoda ne bi htio pročitati scenarij, on ne pripada u .feature fajl.

Ukratko – 10.9 Koraci u Pythonu i pytest-bdd

  • Biblioteka pytest-bdd povezuje svaki korak scenarija s Python funkcijom i pravi pytest testove.
  • Parametri koraka, kao {iznos}, prenose vrijednosti iz rečenice u funkciju.
  • Četiri scenarija DeliveryApp daju osam testova, a nad prvom verzijom šest pada.
  • Najveća vrijednost BDD-a je zajednički razgovor o primjerima prije pisanja koda.
  • U Gherkin idu scenariji važni korisniku, a detaljni testovi ostaju u pytestu.

Provjeri se

  1. Šta je kriterij prihvatanja? Konkretan, provjerljiv uslov koji korisnička priča mora ispuniti da bi bila gotova.
  2. Kako se na bosanskom pišu Given, When, Then u Gherkinu? Dato, Kada, Zatim.
  3. Koliko testova pravi Scenariju-obris s tabelom od pet redova? Pet, jedan za svaki red.

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

Praksa · Sedmica 10

Praktična nastava – Sistem, opterećenje i prihvatanje

Praktična nastava – Sistem, opterećenje i prihvatanje

Cilj je pokrenuti sistemski test s pravim serverom, izmjeriti performanse DeliveryApp Locustom, prijaviti sigurnosni nalaz i napisati BDD scenarije za novu korisničku priču. Radi se u parovima. Prije početka: pip install fastapi uvicorn locust pytest-bdd.

Korak 1 – Sistemski test (30 minuta)

  1. U primjeri/deliveryapp pokrenite pytest -v tests_sistem nad ispravnom i nad prvom verzijom. Zapišite rezultate.
  2. Dodajte sistemski test: narudžba N-1002 (4 × Ćevapi, 2,5 km) prolazi put NOVA → PRIHVAĆENA → OTKAZANA. Očekivani iznos i stanja zapišite prije pokretanja.
  3. Pokušajte pokrenuti test dok je port 8765 zauzet (pokrenite prije toga uvicorn api:app --port 8765 u drugom terminalu). Šta se desi? Kakav je to nalaz: greška u kodu ili u okruženju?

Korak 2 – Locust (45 minuta)

  1. Pokrenite server (uvicorn api:app --port 8000) i Locust s grafičkim prikazom (locust -f locustfile.py --host http://127.0.0.1:8000), otvorite http://localhost:8089, unesite 200 korisnika i 20 u sekundi.
  2. Poslije jedne minute zapišite: broj zahtjeva, greške, propusnost, medijan, 95. percentil. Da li je NZ-1 ispunjen?
  3. Stres: povećavajte broj korisnika (500, 1000, 2000…) dok vrijeme odziva ne poraste ili se ne pojave greške. Zapišite gdje je granica na vašem računaru i ko je „pukao” prvi: server ili sam Locust (pogledajte opterećenje procesora u Task Manageru).
  4. Dodajte u locustfile.py radnju koja provjerava kod STUDENT10 (ukupno mora biti 2235) i pokrenite ponovo.

Korak 3 – Sigurnost (30 minuta)

  1. Preko stranice /docs napravite narudžbu, pa je, bez ikakve prijave, proglasite isporučenom. Napišite izvještaj o defektu (šablon iz poglavlja 3) s ozbiljnošću, prioritetom i koracima.
  2. Pošaljite narudžbu u kojoj je kupac vrlo dug tekst (10 000 znakova) i tekst <script>alert(1)</script>. Šta API vraća? Šta bi se moglo desiti kad web stranica prikaže to ime? Zapišite kao pitanje za tim.

Korak 4 – BDD (60 minuta)

  1. Pokrenite pytest -v tests_bdd nad obje verzije i uporedite padove s listom D-01 … D-05 iz poglavlja 8.
  2. U trojkama (vlasnik proizvoda, programer, tester) napišite fajl features/napojnica.feature za priču: „Kao kupac, želim ostaviti napojnicu dostavljaču, da bih ga nagradio za brzu dostavu.” Kriteriji iz PP-8. Bar jedan Scenario i jedan Scenariju-obris s pet primjera (među njima granice 66,00 € i 66,01 € za 15 %, vježba 2 poglavlja 8).
  3. Napišite korake u test_napojnica_bdd.py koji koriste funkciju napojnica iz poglavlja 5 i pokrenite ih.
  4. Dajte .feature fajl kolegi iz druge grupe koji nije učestvovao. Može li ga razumjeti bez objašnjenja? Šta je bilo nejasno?

Rezultat koji se predaje: fajl rezultati-10.md s rezultatima sistemskog testa i opisom problema sa zauzetim portom; tabela mjerenja Locusta za 200 korisnika i granica iz testa stresa; izvještaj o sigurnosnom defektu; features/napojnica.feature i test_napojnica_bdd.py s rezultatom pokretanja; komentar kolege o razumljivosti scenarija.

Vježbe

Vježbe za studenta

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

Vježba za studenta 1 – vrsta testa.

Zadatak

Koja je vrsta testa: a) 150 korisnika 12 sati, prati se memorija servera; b) za 10 sekundi broj korisnika skoči sa 50 na 2000; c) korisnici se dodaju dok vrijeme odziva ne pređe 5 s; d) 200 korisnika, provjerava se NZ-1; e) vlasnik restorana R-2 sedmicu dana prima narudžbe preko aplikacije.

Vježba za studenta 1 – vrsta testa. – rješenje

Rješenje (R)

a) izdržljivost; b) skok; c) stres; d) opterećenje; e) korisničko prihvatno testiranje (UAT), ili beta, ako su uključeni i pravi kupci.

Vježba za studenta 2 – percentili.

Zadatak

Deset zahtjeva trajalo je (u ms): 20, 22, 25, 25, 30, 31, 35, 40, 45, 3000. Koliki je prosjek, a koliki medijan? Šta bolje opisuje iskustvo korisnika?

Vježba za studenta 2 – percentili. – rješenje

Rješenje (R)

Zbir je 3273 ms, prosjek 327,3 ms. Medijan (prosjek 5. i 6. vrijednosti) je 30,5 ms. Medijan opisuje tipičnog korisnika (oko 30 ms), a prosjek je „naduvan” jednim zahtjevom od 3 s. Ali ni medijan ne pokazuje tog jednog korisnika koji je čekao 3 s; zato se gledaju i visoki percentili (95., 99.) i maksimum.

Vježba za studenta 3 – nefunkcionalni zahtjev.

Zadatak

Prepravite zahtjev „Aplikacija mora biti brza i podnositi mnogo korisnika” tako da se može testirati.

Vježba za studenta 3 – nefunkcionalni zahtjev. – rješenje

Rješenje (R)

Npr.: „Pri 500 istovremenih korisnika, od kojih svaki napravi radnju svakih 1 do 3 sekunde, 95 % zahtjeva za cijenu i narudžbu završava za najviše 1 sekundu, 99 % za najviše 3 sekunde, a udio grešaka je manji od 0,1 %.” Zahtjev ima broj korisnika, ponašanje korisnika, percentile, granice vremena i dozvoljene greške.

Vježba za studenta 4 – Gherkin.

Zadatak

Napišite scenarij na bosanskom za pravilo PP-1 (najmanja narudžba 5,00 €), s granicom.

Vježba za studenta 4 – Gherkin. – rješenje

Rješenje (R)
# language: bs
Karakteristika: Najmanja narudžba
  Scenariju-obris: Narudžba ispod 5,00 € se odbija
    Dato korpa od <iznos> €
    I adresa udaljena 2 km
    Kada kupac zatraži cijenu
    Zatim narudžba je <ishod>

    Primjeri:
      | iznos | ishod      |
      | 4,99  | odbijena   |
      | 5,00  | prihvaćena |

Za korak „narudžba je …” treba nova funkcija koraka koja hvata ValueError (kao korak za otkazivanje u test_dostava_bdd.py).

Vježba za studenta 5 – okruženje.

Zadatak

Tim je za testno okruženje kopirao produkcijsku bazu DeliveryApp sa svim kupcima, adresama i brojevima telefona, „da testovi budu realni”. Šta nije u redu i kako to uraditi ispravno?

Vježba za studenta 5 – okruženje. – rješenje

Rješenje (R)

Stvarni lični podaci kupaca ne smiju biti u testnom okruženju bez zakonskog osnova i zaštite (GDPR, zakon o zaštiti ličnih podataka u BiH): više ljudi ima pristup, zaštita je slabija, a podaci mogu procuriti. Ispravno: izmišljeni podaci (K-01 … K-05, adrese kao „Lipa 12”) ili anonimizovana kopija u kojoj su imena, adrese i telefoni zamijenjeni, a zadržani su samo struktura i količina podataka potrebni za test performansi.

Sažetak u pet rečenica

  1. Healthcare.gov je 2013. pao prvog dana jer cijeli sistem nije na vrijeme testiran pod pravim opterećenjem, a test koji je pokazao pad s nekoliko stotina korisnika nije zaustavio otvaranje.
  2. Sistemsko testiranje provjerava sklopljen sistem u okruženju sličnom produkciji, a sistemski test DeliveryApp pokreće pravi server i prolazi cijeli put narudžbe preko mreže.
  3. Nefunkcionalno testiranje mjeri performanse (opterećenje, stres, skok, izdržljivost), sigurnost i upotrebljivost, a Locust je pokazao da 95 % zahtjeva DeliveryApp završi za 16 ms pri 200 korisnika, uz napomenu da rezultat važi samo za to okruženje.
  4. Sigurnosni pregled po OWASP Top 10 otkrio je pravi propust u API-ju DeliveryApp: svako može promijeniti stanje bilo koje narudžbe.
  5. Prihvatno testiranje odlučuje da li korisnik prihvata sistem, a BDD piše kriterije prihvatanja kao Gherkin scenarije na bosanskom (Dato, Kada, Zatim), koje razumiju svi i koje pytest-bdd izvršava kao testove.

Pitanja za ponavljanje

  1. Zašto je Healthcare.gov pao i šta to govori o sistemskom testiranju?
  2. Šta je sistemsko testiranje i po čemu se razlikuje od integracionog?
  3. Koja okruženja postoje i zašto testno okruženje mora ličiti na produkciju?
  4. Zašto stvarni podaci kupaca ne smiju u testno okruženje?
  5. Šta radi sistemski test DeliveryApp i šta može otkriti, a TestClient ne može?
  6. Kako izgleda dobro napisan nefunkcionalni zahtjev? Navedite NZ-1.
  7. Objasnite četiri vrste testova performansi.
  8. Kako se u Locustu opisuje korisnik? Šta znače težine u @task?
  9. Šta je 95. percentil i zašto je bolji od prosjeka?
  10. Zašto rezultat testa performansi API-ja DeliveryApp ne znači da će pravi sistem podnijeti 200 korisnika?
  11. Šta je OWASP Top 10? Koji propust ima API DeliveryApp?
  12. Kako se testira upotrebljivost, a šta je pristupačnost?
  13. Navedite vrste prihvatnog testiranja. Šta su kriteriji prihvatanja?
  14. Šta je BDD? Objasnite Gherkin scenarij i kako ga pytest-bdd pretvara u test.