Test-Driven Development
vývoj riadený testami, black-box testing
Videá pre cvičenie
About
Jedna z agilných metodík, ktorá je v praxi bežne používaná, sa nazýva vývoj riadený testami (z ang. test driven development), kedy sa voči známemu rozhraniu najprv napíšu testy a až tak sa vytvára samotná implementácia. Výsledný kód a jeho aktualizácie sú tak neustále kontrolované voči očakávanému správaniu zapísanému v testoch. Ak dôjde zmenou kódu ku chybe, tá je okamžite odhalená pri spustení testov.
Túto metodiku používame aj pri testovaní vašich zadaní v Aréne a na tomto cvičení vám pomôžeme si ju osvojiť.
Objectives
- Porozumieť základom agilnej metodiky vývoja riadeného testami.
- Naučiť sa vytvárať testy v jazyku C pomocou knižnice
assert.h
- Vytvoriť vlastné jednotkové (unit) testy funkcií.
Postup
Warm up!
Predtým, ako sa budeme snažiť osvojiť si vývoj riadený testami,
pripravíme si pracovné prostredie. Preto v tomto kroku stiahnete svoj
projekt z git-u a počas cvičenia budete pracovať v priečinku so
zadaním Top Secret (ps1/
).
Úloha
Stiahnite, resp. naklonujte si svoj projekt z git-u.
V prípade, ak ste ešte nezačali riešiť toto zadanie, stiahnite si zo
stránky so zadaním Top
Secret kostru projektu a umiestnite ju do priečinku
ps1/
vášho projektu.
Úloha
V priečinku ps1/
, ktorý obsahuje zdrojové kódy zadania
Top Secret vytvorte súbor tests_bmp.c
a pridajte
ho do projektu na git.
Tento súbor bude obsahovať implementácie testov pre testovanie
funkcií projektu Top Secret. Bude ho však možné preložiť a
spustiť samostatne, preto v ňom vytvorte hlavnú funkciu
main()
. V tele funkcie vypíšte na obrazovku dve správy:
Tests started...
All tests passed
Poznámka
Pre úspešné odovzdanie a hodnotenie projektu tento súbor nie je dôležitý. Ak ho teda pridať do projektu zabudnete alebo jednoducho tento krok ignorujete, nebudete za to nijakým spôsobom postihnutí v hodnotení.
Úloha
Do súboru Makefile
pridajte nové pravidlo
tests
, pomocou ktorého testy preložíte a následne ich po
úspešnom preklade aj spustíte.
Pravidlo bude teda obsahovať dva riadky (príkazy):
- preklad testov
- spustenie testov
V tomto prípade vieme využiť vlastnosť nástroja make
, že
ak dôjde pri vykonávaní jedného príkazu k chybe, žiadny ďalší príkaz
nebude vykonaný. To znamená, že ak bude preklad neúspešný, k spusteniu
testov nedôjde.
Do prekladu a teda aj závislostí zahrňte súbory bmp.c
a
tests_bmp.c
.
Úloha
Overte správnosť svojej implementácie.
Testy spustíte spustením príkazu make
a príslušného
pravidla v tvare:
make tests
Ak ste postupovali správne a neurobili ste žiadnu chybu, na obrazovke sa vypíše:
Tests started...
All tests passed
Úloha
Aktualizujte pravidlo clean
súboru Makefile
o zmazanie spustiteľného súboru tests
.
Caesar
Bolo by super, keby naše programy vždy fungovali na prvýkrát :-) Keďže to tak v skutočnosti nefunguje, náš kód potrebujeme testovať a ladiť, aby sme odhalili a minimalizovali vzniknuté chyby. Aby sme mohli náš kód testovať a ladiť, musí v prvom rade fungovať! (musí byť spustiteľný) V prvom kroku vytvoríte testy pre implementáciu cézarovej šifry, s ktorou ste sa už stretli, a ktorá tvorí základ pre vytvorenie Vigenèrovej šifry.
Úloha
V súbore bmp.c
vytvorte (zatiaľ) prázdnu definíciu
funkcie char* caesar_encrypt()
.
Funkcia bude mať tieto parametre:
text
- vstupný parameter reprezentujúci text, ktorý má byť zakódovanýstep
- vstupný parameter reprezentujúci posun v smere doprava
Funkcia bude vracať referenciu na zakódovaný text pomocou Cézarovej šifry.
Úloha
V súbore tests_bmp.c
vytvorte funkciu
void test_simple_encrypt()
, ktorá otestuje správnosť
implementácie Cézarovej šifry prostredníctvom makra
assert()
. Táto funkcia nebude mať žiadne parametre a
nevráti žiadnu hodnotu. Bude reprezentovať jednoduchý test funkcie
caesar_encrypt()
, ktorú zavolá s textom na zakódovanie a
tento potom porovná s očakávaným.
Pre použitie makra assert()
potrebujete vo svojom kóde
použiť štandardnú knižnicu assert.h
.
Pre overenie správnosti fungovania funkcie môžete využiť s výhodou
linuxový nástroj tr
. Ak budete chcieť otestovať správanie
vašej funkcie pre posun 5, použitie nástroja tr
bude nasledovné:
tr A-Z F-ZA-E
Úloha
Overte funkčnosť riešenia.
Poznámka
Testy by mali byť neúspešné (došlo k výpisu chyby), pretože ste testovali prázdnu funkciu.
Výpis môže vyzerať nasledovne:
Tests started...
Encrypting constant string...
tests: test_bmp.c:19: test_simple_encrypt: Assertion `strcmp("FMTO",result) == 0' failed.
Aborted (core dumped)
Úloha
Rýchlo upravte funkciu caesar_encrypt()
tak, aby bol
test úspešný.
Výpis môže vyzerať nasledovne:
Tests started...
Encrypting constant string...
Passed
All tests passed
Úloha
Pridajte do programu zoznam slov a ich šifrovanej podoby, a otestujte
riešenie na všetkých slovách v novej funkcii
void test_caesar_encrypt()
.
Použiť môžete nasledujúce zoznamy:
const char words[10][10] = { "SEPTEMBER", "THOUSAND", "CASSOVIA", "NEPAL", "EVEREST",
"CAESAR", "ZONE", "YES", "ANDERSON", "KEY" };
const char en_words[10][10] = { "XJUYJRGJW", "YMTZXFSI", "HFXXTANF", "SJUFQ", "JAJWJXY",
"HFJXFW", "ETSJ", "DJX", "FSIJWXTS", "PJD" };
Úloha
Overte funkčnosť riešenia.
Poznámka
Testy by mali byť neúspešné (došlo k výpisu chyby), pretože aktuálna implementácia zahŕňa len jednu situáciu.
Výpis môže vyzerať nasledovne:
Tests started...
Encrypting constant string...
Passed
Encrypting set of strings...
tests: test_bmp.c:29: test_caesar_encrypt: Assertion `strcmp(en_words[idx],result) == 0' failed.
Aborted (core dumped)
Úloha
Upravte riešenie cézarovej šifry tak, aby bolo univerzálne a vyhovovalo testom.
Použiť môžete nasledujúcu implementáciu:
char* caesar_encrypt(const char* text, int step){
int len = strlen(text);
char* result = (char*)calloc(len + 1, sizeof(char));
for( int index = 0; index < len; index++ ){
[index] = (text[index] - 'A' + step) % 26 + 'A';
result}
[len] = '\0';
result
return result;
}
Úloha
Overte funkčnosť riešenia.
Poznámka
Testy by mali byť opäť úspešné (nedošlo k výpisu chyby). Váš test sa však venoval iba obmedzenej skupine slov.
Výpis môže vyzerať nasledovne:
Tests started...
Encrypting constant string...
Passed
Encrypting set of strings...
Passed
All tests passed
Úloha
Vytvorte prázdnu funkciu
char* caesar_decrypt(const char* text, const int step)
pre
dešifrovanie a v novej funkcii void test_encrypt_decrypt()
otestujte kombináciu šifrovania a dešifrovania.
Poznámka
Ak dešifrujete zašifrované slovo, výsledkom by malo byť pôvodné slovo.