Table of Contents

Testovaní softwaru

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.)

Rosemary's Grocery Store

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.

Zboží

Každé zboží nebo předmět, které má Rosemary na skladě, budeme reprezentovat instancí třídy 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

Speciální předměty

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ří

Tyto předměty jsou zvláštní v tom, že se chovají (stárnou) jinak než normální zboží.

Aktualizace kvality

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:

>>> 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.

Pravidla aktualizace

Funkce update() musí dodržet následující pravidla:

Váš úkol

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.

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é!

Obsah modulu s testy

Specifikace:

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.

Jak budeme vaše testy testovat?

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