Search
Cílem cvičení je procvičit si na příkladu, jak přetavit specifikace ve formě textového popisu do testů, které ověří shodu implementace se specifikacemi. (Jde především o princip vytváření testů; zde použitá realizace testů je zvolena z důvodu jednoduchosti.)
Dostali jste se do týmu, který vyvíjí počítačovou hru. Rosemary je obchodnice, která v této hře vede obchůdek se smíšeným zbožím (jehož implementaci máte ve správě). Obchod prodává především potraviny (tzv. normal items), ale Rosemary umí sehnat a nabídnout také jisté speciální předměty. Rosemary je pečlivá a vede si evidenci o stavu zboží, které má na skladě. Na konci každého dne stav všeho zboží aktualizuje.
Každé zboží nebo předmět, které má Rosemary na skladě, budeme reprezentovat instancí třídy Item:
Item
class Item: def __init__(self, name, days_left, quality): self.name = name self.days_left = days_left self.quality = quality
Každé zboží či předmět má tedy
name
days_left
quality
Rosemary může mít na skladě i speciální předměty, které se určují podle specifického jména. Mezi tyto speciální předměty patří
“Aged Brie”
“Diamond”
“Tickets”
Tyto předměty jsou zvláštní v tom, že se chovají (stárnou) jinak než normální zboží.
Ve hře se na konci každého dne zavolá pro každé zboží na skladě funkce update(). Ta aktualizuje (obvykle sníží) hodnoty days_left a quality:
update()
>>> bread = Item('Bread', days_left=3, quality=5) >>> update(bread) >>> print(bread.days_left) 2 >>> print(bread.quality) 4
Poznámka 1: Funkce update() je modifikátorem, tj. nic nevrací, ale přímo na místě modifikuje instanci třídy Item, kterou jí předáme jako argument.
Poznámka 2: Z hlediska objektového návrhu by bylo lepší, kdyby update() byla metodou ve třídě Item a kdybychom mohli od třídy Item odvodit další třídy, např. BrieItem, DiamondItem, apod., které by věděly, jak sami sebe aktualizovat. Celý zbytek hry ale využívá pouze Item ve formě uvedené výše; zde popsané změny by si vyžádaly dalekosáhlé úpravy v kódu celé hry, a proto je zatím nemáme právo udělat.
Funkce update() musí dodržet následující pravidla:
days_left == 0
Funkce update() už je implementována. Vaším úkolem je sestavit sadů testů pro tuto funkci, které ověří, že se implementace funkce chová podle specifikací. Konkrétně je vaším úkolem vytvořit modul test_rosemary.py s co nejúplnější sadou testů, který nahrajete do BRUTE, kde vám oznámíme, jak dobrou sadu testů máte.
test_rosemary.py
Při testování softwaru je ideální v každém testu testovat pouze jedinou věc tak, aby při selhání testu bylo ihned zřejmé, co je špatně. (Kdyby měl test mnoho možností, proč selhat, netušili byste, která z nich za selhání může.) Je proto zcela obvyklé mít hodně testů a mít je krátké!
Specifikace:
update
rosemary.py
inspect
importlib
test_
True
False
Traceback (most recent call last): File "check_test.py", line 128, in run_test result = getattr(module, fn.fn_name)()
Vzor souboru test_rosemary.py:
from rosemary import Item, update def test_normal_item_decreases_days_left(): # Prepare for the test item = Item('Bread', days_left=3, quality=5) # Call to the tested function update(item) # Check the specification return item.days_left == 2 def test_... ... def test_... ...
Poznámka: Zde se zcela obejdeme bez jakéhokoli testovacího frameworku, dokonce i bez modulu testing.py, který jsme si vytvářeli na přednášce.
testing.py
Jak už bylo řečeno, v BRUTE k vašemu testovému modulu test_rosemary.py připojíme naši implementaci funkce update() v modulu rosemary.py. Máme k dispozici nejen (snad) správnou implementaci, ale i mnoho chybných s mnoha různými chybami. Vaši sadu testů vyzkoušíme na všech implementacích funkce update(). Cílem je, aby