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
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. | Poglavlje | Teorija (3 časa) | Praksa (3 časa) |
|---|---|---|---|
| 1 | Zašto testiramo | Uvodne priče; greška, defekt, otkaz; sedam principa; DeliveryApp | Tabela očekivanih cijena rukom |
| 2 | Proces i nivoi | Test proces; nivoi i V-model; vrste; statičko testiranje | Recenzija zahtjeva DeliveryApp |
| 3 | Manuelno testiranje | Test slučaj; izvještaj o defektu; istraživačko testiranje | Test slučajevi za web stranicu |
| 4 | Automatizovano testiranje | Šta automatizovati; piramida testova; prvi test | Prvi pytest |
| 5 | Jedinično testiranje | AAA; fixture, parametri, izuzeci; TDD | Testovi za dostavu i popust |
| 6 | Bijela kutija | Graf toka; pokrivenost; ciklomatska složenost | coverage.py do 100 % grana |
| 7 | Tok podataka | Definicija i upotreba; anomalije; statička analiza, mutacije | ruff, mypy, ručna mutacija |
| 8 | Crna kutija | Ekvivalencija i granice; tabela odlučivanja; stanja | Lov na pet grešaka |
| Sed. | Poglavlje | Teorija (3 časa) | Praksa (3 časa) |
|---|---|---|---|
| 9 | Model i integracija | Model; strategije integracije; API | TestClient za API |
| 10 | Sistemsko testiranje | Sistemsko; performanse i sigurnost; prihvatno i BDD | Locust, Gherkin |
| 11 | OO testiranje | Stanje objekta; nasljeđivanje; dvojnici | Narudzba, unittest.mock |
| 12 | Paralelne aplikacije | Trka podataka; zastoj; nestabilni testovi | Niti, 1000 ponavljanja |
| 13 | Web aplikacije | Web i DOM; Playwright; Page Object, pristupačnost | Playwright za DeliveryApp |
| 14 | Upravljanje testiranjem | Test plan i rizik; metrike; CI/CD | GitHub Actions |
| 15 | Alati, AI, projekat | Pregled alata; AI u testiranju; ISTQB | Odbrana projekta |
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.

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.
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.
| Čas | Sadržaj | Na času |
|---|---|---|
| Teorija 1 | 10.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 2 | 10.4–10.6 Performanse i Locust; sigurnost; upotrebljivost | 200 korisnika na DeliveryApp |
| Teorija 3 | 10.7–10.9 Prihvatno testiranje; kriteriji prihvatanja; BDD i Gherkin | Scenarij „Dato – Kada – Zatim” |
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:
| Integraciono | Sistemsko | |
|---|---|---|
| Šta se testira | saradnja dva ili više dijelova | cijeli sistem |
| Ko obično testira | programeri | nezavisni testni tim |
| Spoljni servisi | često dvojnici | pravi ili vjerne kopije |
| Okruženje | računar programera | testno okruženje slično produkciji |
| Zahtjevi | funkcionalni (š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.
Program koji radi „na mom računaru” ne mora raditi na serveru. Zato sistemi obično imaju nekoliko okruženja:
| Okruženje | Za šta | Podaci |
|---|---|---|
| razvojno (development) | programer piše i probava kod | izmišljeni, mali |
| testno (test, QA) | testeri testiraju novu verziju | testni skup (N-1001, K-01…) |
| predprodukcijsko (staging) | posljednja proba, što sličnije produkciji | kopija strukture produkcije, bez stvarnih ličnih podataka |
| produkcijsko (production) | stvarni korisnici | stvarni |
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:
Š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:
@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"]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.92sNad 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.70sIsti 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.
Š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.
scope="module" pokreće server jednom za sve testove u fajlu.scope="module"? Da se server pokrene jednom za sve testove u fajlu, jer pokretanje traje.Odgovori: tipka R ili klik na zamućeno polje.
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):

| Vrsta | Pitanje | DeliveryApp |
|---|---|---|
| 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:
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)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:8000Skraćen rezultat jednog mjerenja na laptopu:
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
Kako čitati:
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.
„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.
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:
| Kategorija | Pitanje za DeliveryApp | Stanje u našem API-ju |
|---|---|---|
| pokvarena kontrola pristupa | mož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 dizajn | vjeruje li server cijeni koju šalje klijent? | ne: server sam računa cijenu (dobro) |
| pogrešna podešavanja | da li greška otkriva detalje servera? | FastAPI ne vraća trag greške korisniku (dobro) |
| ranjive komponente | koriste 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.
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.
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:
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”.
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.
Odgovori: tipka R ili klik na zamućeno polje.
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:
| Vrsta | Ko testira | Primjer za DeliveryApp |
|---|---|---|
| korisničko (UAT) | stvarni korisnici ili njihovi predstavnici | vlasnici tri restorana probaju aplikaciju sedmicu dana |
| operativno | administratori i podrška | rezervne kopije, vraćanje poslije pada, nadzor servera |
| ugovorno | naručilac prema ugovoru | grad koji je naručio aplikaciju provjerava stavke ugovora |
| regulatorno | prema zakonu ili standardu | zaštita ličnih podataka, fiskalni računi |
| alfa | korisnici, kod proizvođača | studenti EUBD-a naručuju u učionici |
| beta | korisnici, u stvarnom svijetu | 100 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:
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”.
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:
| Engleski | Bosanski | Značenje |
|---|---|---|
| Feature | Karakteristika | šta opisujemo (korisnička priča) |
| Scenario | Scenario | jedan primjer ponašanja |
| Given | Dato | početno stanje (pripremi) |
| When | Kada | radnja korisnika (izvrši) |
| Then | Zatim | očekivani ishod (provjeri) |
| And, But | I, Ali | nastavak prethodnog koraka |
| Scenario Outline, Examples | Scenariju-obris, Primjeri | jedan scenarij za tabelu primjera |
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:
# 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 |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 €.
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:
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)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;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.
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.
„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.
{iznos}, prenose vrijednosti iz rečenice u funkciju.Odgovori: tipka R ili klik na zamućeno polje.
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.
primjeri/deliveryapp pokrenite pytest -v tests_sistem nad ispravnom i nad prvom verzijom. Zapišite rezultate.uvicorn api:app --port 8765 u drugom terminalu). Šta se desi? Kakav je to nalaz: greška u kodu ili u okruženju?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.locustfile.py radnju koja provjerava kod STUDENT10 (ukupno mora biti 2235) i pokrenite ponovo./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.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.pytest -v tests_bdd nad obje verzije i uporedite padove s listom D-01 … D-05 iz poglavlja 8.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).test_napojnica_bdd.py koji koriste funkciju napojnica iz poglavlja 5 i pokrenite ih..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.
Rješenja su sakrivena – tipka R ili klik na okvir.
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.
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.
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?
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.
Prepravite zahtjev „Aplikacija mora biti brza i podnositi mnogo korisnika” tako da se može testirati.
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.
Napišite scenarij na bosanskom za pravilo PP-1 (najmanja narudžba 5,00 €), s granicom.
# 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).
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?
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.
@task?