Vianoce v ITnetwork sú tu! Dobí si teraz kredity a získaj až 80 % extra kreditov na e-learningové kurzy ZADARMO. Zisti viac.
Hľadáme nové posily do ITnetwork tímu. Pozri sa na voľné pozície a pridaj sa k najagilnejšej firme na trhu - Viac informácií.

12. diel - Ako testovať programy v C (knižnica assert.h) 2. časť

V minulej lekciám, Ako testovať programy v C (knižnica assert.h) , sme si Povedala o testovaní v céčku a vyskúšali sme si takzvaný Glass-box Testing. Dnes si povieme o test riadenom vývoji - (test-driven development - TDD).

TDD je technika tvorby softvéru, ktora bola navrhnutá s cieľom umožniť čo Najrýchlejšie zistenie a opravením chýb.Spravidla sa testy píšem este pred samotnou implementácie, ktora musí pred odovzdaním Všetky testy Prejsť. Vytvárané kód sa tu testuje už od zaciatku programovaním, nie až po dokončení celého modulu. Tento prístup by teda mal obmedziť neskorý odstraňovaním chýb na minimum, čím sa ušetríme vzácne zdroje - čas, pracovná sila ai Peniaze.

Tento Spôsob Testovanie sa nazýva ai Black-box Testing, pretoze modul (funkciám) je čierna skrinka a nevidíme do naj (niekedy este funkciám ani nie je napisane).

Black-box Testing - Pokročilé konštrukcia jazyka C

Parsing

Napadlo ma, že by sme si mohli Napísať pomocný kniznica na parsovanie vstupov od užívateľov.

Tak ideme na to, nie? :-)

Založme si v IDE nový projekt s názvom Parsing, pridáme doňho header Súbor parse.h a hlavný source Súbor (obsahuje funkciám main ()) premieňajú na parse.c.
Žiadny ďalší Súbor nebudú potrebovať, pretoze použijeme podmienený preklad za pomoci funkcií preprocesoru.

Súbor parse.h bude vyzera takto:

#ifndef PARSING_H_INCLUDED
#define PARSING_H_INCLUDED
/**
* Funkcia skontroluje, či vstupný reťazec obsahuje iba číslice,
* ak nie, prvý odlišný znak zapíše na prvú pozíciu reťazca
* @param vstupný reťazec (vstupno - výstupný parameter)
* @return reťazec prevedený na int ak reťazec obsahuje iba číslice, inakšie 0
*/
int parse_int(char *number);
/**
* Funkcia skontroluje, či reťazec obsahuje iba jednu desatinnú bodku,
* ak ich obsahuje viac, vyhodnotí to ako chybu,
* skontroluje, či obsahuje namiesto botky čiarku, ak áno, prepíše ju na bodku,
* skontroluje, či vstupný reťazec obsahuje iba číslice (okrem jednej botky),
* ak nie, prvý odlišný znak zapíše na prvú pozíciu reťazca
* @param vstupný reťazec (vstupno - výstupný parameter)
* @return reťazec prevedený na double ak reťazec obsahuje iba číslice,
* alebo číslice a jednu bodku, inakšie 0
*/
double parse_double(char *number);
#endif // PARSING_H_INCLUDED

Súbor parse.c bude na zaciatky vyzera takto:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include "parsing.h"
#define TESTY // pri zakomentovaní budú testy odstavené

int parse_int(char *number)
{
    return atoi(number); // prevedie reťazec na int
}

#ifdef TESTY
#define TESTY

int main()
{
    char *cislo1;

    cislo1 = (char*)malloc(10);
    strcpy(cislo1, "123456");
    assert(parse_int(cislo1) == 123456);
    printf("Testy presli.\n");
    free(cislo);
}

#endif // TESTY

Uložiť, skompilovat a spustiť.

Konzolová aplikácia
Testy presli.

=> Testy prešlo. A máme hotovo! :-)

Ak chcete správne pochopiť Testovanie, bolo by dobré, keby ste Všetky kroky robili spolu so mnou.

Skus pridá ďalšie test:

cislo2 = (char*)malloc(10);
strcpy(cislo2, "123456x");
assert(parse_int(cislo2) == 0);

výstup:

Konzolová aplikácia
Assertion failed: parse_int(cislo2) == 0, file C:\Users\libcosenior\Documents\cecko\Parsing\parsing.c, line 26

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

A máme Assertion failed. Prečo? Reťazec obsahuje iný znak Ako číslicu a návratová hodnota má čo i 0 (nula).
Skus teda upraviť kód, napríklad takto:

if (atoi(number))
    return atoi(number);
else
    return 0;

Aaa zase chyba. Čo sa stalo? Zistíme to tak, že si vypíšeme reťazec prevedený na číslo, pridáme výpis do Funkcie main ():

char *cislo2 = "123456x";
printf("retazec\t%s\ncislo\t%d\n", cislo2, atoi(cislo2));
assert(parse_int(cislo2) == 0);

výstup:

Konzolová aplikácia
retazec 123456x
cislo   123456
Assertion failed: parse_int(cislo2) == 0, file C:\Users\libcosenior\Documents\cecko\Parsing\parsing.c, line 27

A hneď vidíme kde je problém. Funkciám atoi () vzala do úvahy číslice, ktore bolí pred znakom x.
Ako to riešiť? Vyskusam zmeniť hodnotu * číslo2 na "123x456" a otestujeme.

výstup:

Konzolová aplikácia
retazec 123x456
cislo   123
Assertion failed: parse_int(cislo2) == 0, file C:\Users\libcosenior\Documents\cecko\Parsing\parsing.c, line 27

Problém je tu stále. Funkciám atoi () prevedie číslice, ktore ŠÚ pred jedinou znakom na číslo, Preto teraz presunieme ten znak na zaciatok reťazca: char * číslo2 = "x123456";

výstup:

Konzolová aplikácia
retazec x123456
cislo   0
Testy presli.

Testy prešli a teraz už vieme, že ak je v reťazci iný znak Ako číslice, treba ho vložiť na zaciatok reťazca.
Vyskúšajme upraviť funkciám takto:

for (int i = 0; i < strlen(number); i++) {
    if (!isdigit(number[i])) { // znak nie je číslica
        number[0] = number[i];
        break;
    }
}
if (atoi(number)) {
    return atoi(number);
}
else
    return 0;

výstup:

Konzolová aplikácia
retazec 123x456
cislo   123
Testy presli.

Čo sa deje? Prečo je číslo 123 a nie 0, pričom testy prešlo? Všetko je v poriadku, ľan som zabudol zmazať (zakomentovať) Riadok s výpisom a ten neberie výstupy z funkciám.

Fajn. Zdá sa, že prvá funkciám je bezchybná. Napriek tomu by možno bolo ešte dobré to poriadne otestovať napríklad tak, že do textového subor napíšeme 100 rôznych reťazcov a tie sa buduje postupne testovať.

RGR systém

Videli sme, že funkció píšeme tak, aby prešla prvým testom skoro za každú cenu. Potom pridáte ďalšie test a tak Ďalej až do úspešného konca.

Tento systém sa nazýva RGR systém.

RGR systém - Pokročilé konštrukcia jazyka C
  • RED - napíšte malý test, ktory nefunguje a na prvýkrát možné ani nepojde preložiť
  • GREEN - rýchle spojazdnite test a neváhajte pri tom urobit hocijaka somariny
  • Refactor - zbavte sa vsetkych duplicitu vytvorených v Snaha spojazdniť test

A tak stále dookola, kým nie je kód bezchybný.

Aby sme sa s tím Lepšie stotožnili, TDD sposobom si napíšeme ai druhý funkciám.

Pridáte si ju do subor parsing.c:

double parse_double(char *number)
{

}

a napíšeme prvý test.

/** testy funkcie int parse_double(char *number) **/
char *cislo3;

cislo3 = (char*)malloc(10);
strcpy(cislo3, "123.456");
assert(parse_double(cislo3) == 123.456);

Nedá sa to scompilovať, pretoze vo funkciám nemáme návratovú hodnotu. Doplníme.

return atof(number);

Skompilujeme a spustíme. Prešlo. Máme hotovo! :-)

Samozrejme, že nie. Ideme najst Ďalšie Špeciálne zadanie od užívateľov.

strcpy(cislo3, "1.23.45.6");
assert(parse_double(cislo3) == 0);

Assertion failed! V reťazci Moze hoci okrem číslic maximálne jedna bodka (bodka). Čo s tým?

int point = 0;
for (int i = 0; i < strlen(number); i++) {
    if (number[i] == '.')
        point++;
}
if (point > 1)
    return 0;
else
    return atof(number);

Testy prešlo. Už zase máme hotovo. : -` Ďalším užívateľovho špecialitky:

strcpy(cislo3, "123,456");
assert(parse_double(cislo3) == 123.456);

V tomto prípade chceme, aby to vzalo ai tú Ciarka Namiesto botky.
Assertion failed!
Odstránime chybu tím, že doplníme do funkciám.

for (int i = 0; i < strlen(number); i++) {
    if (number[i] == ',')
        number[i] = '.';
}

Testy prešlo. Skus toto:

strcpy(cislo3, "123,45,6");
assert(parse_double(cislo3) == 0);

Assertion failed! Prečo? Vo funkciám treba najskôr ošetriť Ciarka a až potom botky. A bude to v poriadku.

Ďalšie zlé zadanie Moze hoci, že tam budem znaky mimo číslic, čiarok a bodiek.

strcpy(cislo3, "12x3.45,6");
assert(parse_double(cislo3) == 0);

Samozrejme, že je zase chyba. Vyriešime pridaním kódu:

for (int i = 0; i < strlen(number); i++) {
    if (!isdigit(number[i])) {
        number[0] = number[i];
        break;
    }
}

Testy prešlo.
Ale Skus ešte Niečo:

strcpy(cislo3, "12x3456");
assert(parse_double(cislo3) == 0);

Nebude tam Žiadna bodka, čo to spraví? Testy prešlo.

Fajn. Zdá sa, že ai druhá funkciám je bezchybná. Napriek tomu by možno bolo ešte dobré to poriadne otestovať napríklad tak, že do textového subor napíšeme 100 rôznych reťazcov a tie sa buduje postupne testovať.

Pozor dolezite!
Nikdy nezabudnite Nakoniec upraviť kód tak, aby bol čo Najjednoduchšia, aby sa neopakovali Rovňák časti kódu a aby bol dobre okomentovaný. (Môj je priložený.)

Teraz mozem Vypnutie Testovanie tak, že zakomentujeme Riadok:

//#define TESTY // pri zakomentovaní budú testy odstavené

a nepodarí sa nám to ani skompilovat, pretoze projektu CHYBA funkciám main ().
To nateraz nevadí. Niekedy, ked budete pulovr nebo vesta dver Funkcie potrebovať, stačí do projekt pridať obidve subor a v subor, v ktorom sa budem Funkcie používať, includovať parsing.h.

Takže Ako vidíte, Testovanie nás núti premýšľa KÉ všemožné vstupy sa mozu do Funkcie dosť a KÉ to mozem Mať následky na beh programu a núti nás to upraviť kód tak, aby sme Všetky problémy už dopredu vyriešili.

Samozrejme že, vývoj riadeni testami určite nie je univerzálnym liekom na všetko a dosiahnutie želaného efektu v ziadnom pripade nie je zaručené. Ale je to Najlepšia cesta, Ako sa maximálne vyhnutie možným problémom s nefunkčnosťou projektov konečného.

Ked sa nad tím zamyslím, vlastne vývoj všetkého sa testuje. Počnúc hračkami pre deti, cez napríklad Biela techniku, autá, zbrane až po rakety. Kto netestuje, vacsinou odovzdáva nekvalitne Posy a Preto Rýchlo skončí svoju kariéru.

Ja vám vsetkym držím palce pri Pisani svojich ložísk projektovej pomoci TDD.

Na záver prikladám zdrojové kódy napísané v Linux Ubuntu.

V budúcej lekciám, Funkcie s variabilným počtom a Typo argumentovať (stdarg.h) , si ukážeme Ako deklarovať funkciám s variabilným počtom a Typo argumentovať.


 

Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.

Stiahnuť

Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

Stiahnuté 113x (9.15 kB)
Aplikácia je vrátane zdrojových kódov v jazyku C

 

Predchádzajúci článok
Ako testovať programy v C (knižnica assert.h)
Všetky články v sekcii
Pokročilé konštrukcia jazyka C
Preskočiť článok
(neodporúčame)
Funkcie s variabilným počtom a Typo argumentovať (stdarg.h)
Článok pre vás napísal Libor Šimo (libcosenior)
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
Obľúbil som si jazyk C a snažím sa ho spoznať čo najhlbšie. Začal som používať c# WPF, je to krása.
Aktivity