it-swarm-eu.dev

Jsou tvrzení nebo jednotkové testy důležitější?

Tvrdidla i testy jednotek slouží jako dokumentace ke kódové základně a jako prostředek k objevování chyb. Hlavní rozdíly spočívají v tom, že tvrzení fungují jako kontrola rozumnosti a vidí skutečné vstupy, zatímco testy jednotek probíhají na konkrétních simulovaných vstupech a jsou testy na základě jedné dobře definované „správné odpovědi“. Jaké jsou relativní přednosti použití tvrzení vs. jednotkových testů jako hlavního prostředku ověření správnosti? Na co by podle vás mělo být více zdůrazněno?

52
dsimcha

Asserts jsou užitečné pro vyprávění o interním stavu program. Například vaše datové struktury mají platný stav, např. Že datová struktura Time nebude uchovávat hodnotu 25:61:61. Podmínky ověřené tvrzeními jsou:

  • Předpoklady, které zajistí, že si volající zachovává smlouvu,

  • - Postconditions, které zajišťují, že si callee udržuje smlouvu, a

  • Invarianty, které zajišťují, že struktura dat vždy po návratu funkce drží nějakou vlastnost. Invariant je podmínka, která je předpokladem a postcondition.

Testy jednotek jsou užitečné pro vyprávění o vnějším chování modul. Vaše metoda Stack může mít po vyvolání metody Push() konzistentní stav, ale pokud se velikost zásobníku nezvýší o tři po trojnásobném volání, je to chyba . (Například triviální případ, kdy nesprávná implementace Push() _ zkontroluje pouze tvrzení a ukončení.)

Přesně řečeno, hlavní rozdíl mezi tvrzeními a testy jednotek je v tom, že testy jednotek mají data test (hodnoty, které mají spustit program), zatímco tvrzení nikoli. To znamená, že můžete provádět testy jednotek automaticky, zatímco nemůžete říkat totéž pro tvrzení. Kvůli této diskusi jsem předpokládal, že mluvíte o provádění programu v souvislosti s funkčními testy vyššího řádu (které provádějí celý program a neřídí moduly, jako jsou testy jednotek). Pokud nemluvíte o automatizovaných funkčních testech jako o prostředku „vidět skutečné vstupy“, pak je zřejmé, že hodnota spočívá v automatizaci, a tak by testy jednotek vyhrály. Pokud o tom mluvíte v rámci (automatických) funkčních testů, viz níže.

To, co je testováno, se může překrývat. Například postcondition Stack může ve skutečnosti tvrdit, že se velikost zásobníku zvětšuje o jednu. Existují však omezení toho, co lze v tomto tvrzení provést: Měla by také zkontrolovat, zda je právě přidán horní prvek?

Cílem obou je zvýšení kvality. Cílem testování jednotek je najít chyby. Pro tvrzení je cílem usnadnit ladění pozorováním neplatných stavů programu, jakmile k nim dojde.

Všimněte si, že ani technika neověřuje správnost. Ve skutečnosti, pokud provádíte testování jednotek s cílem ověřit správnost programu, pravděpodobně přijdete s nezajímavým testem, o kterém víte, že bude fungovat. Je to psychologický efekt: uděláte cokoli, abyste dosáhli svého cíle. Pokud je vaším cílem najít chyby, vaše aktivity to budou odrážet.

Oba jsou důležité a mají své vlastní účely.

[Jako poslední poznámka k tvrzením: Chcete-li získat co největší hodnotu, musíte je použít ve všech kritických bodech programu, a ne v několika klíčových funkcích. V opačném případě by mohl být původní zdroj problému maskován a obtížně detekovatelný bez hodin ladění.]

43
Macneil

Když mluvíte o tvrzeních, mějte na paměti, že je lze vypnout pouhým přepnutím spínače.

Příklad velmi špatného tvrzení:

char *c = malloc(1024);
assert(c != NULL);

Proč je to špatné? Protože není provedena kontrola chyb, pokud je toto tvrzení přeskočeno kvůli definování NDEBUG.

Test jednotky by (pravděpodobně) jen selhal ve výše uvedeném kódu. Jistě, odvedla svou práci tím, že ti řekla, že se něco pokazilo, nebo že? Jak je pravděpodobné, že malloc() selže při testu?

Tvrzení jsou pro účely ladění, když programátor musí naznačovat, že žádná „normální“ událost by nezpůsobila spuštění tvrzení. malloc() selhání je ve skutečnosti normální událostí, a proto by nikdy nemělo být uplatňováno.

Existuje mnoho dalších případů, kdy se používají tvrzení namísto náležitého zacházení s věcmi, které by se mohly pokazit. To je důvod, proč tvrzení mají špatnou pověst, a proč jazyky jako Go je nezahrnují.

Jednotkové testy jsou navrženy tak, aby vám řekly, když něco, co jste změnili, zlomilo něco jiného. Jsou navrženy tak, aby vás (ve většině případů) zachránili před procházením všemi funkcemi programu (testeři jso důležití pro vydání) pokaždé, když vytvoříte sestavení.

Ve skutečnosti mezi nimi neexistuje žádná jednoznačná korelace, kromě toho, že vám oba řeknou, že se něco pokazilo. Přemýšlejte o prosazení jako o přestávce v něčem, na kterém pracujete, aniž byste museli používat debugger. Představte si test jednotky jako něco, co vám řekne, pokud jste porušili něco, na čem nejste pracujete.

7
Tim Post

Oba nástroje se používají ke zlepšení celkové kvality systému, který vytváříte. Hodně záleží na jazyce, který používáte, na typu aplikace, kterou vytváříte, a na tom, kde se nejlépe tráví váš čas. Nemluvě o tom, že o tom máte několik myšlenkových škol.

Začínáme, pokud používáte jazyk bez klíčového slova assert, nemůžete použít tvrzení (přinejmenším ne způsobem, jakým zde hovoříme). Na dlouhou dobu Java nemělo klíčové slovo assert a řada jazyků stále ne. Testování jednotek se pak stává o něco důležitější. V některých jazycích tvrzení se spouští pouze tehdy, když je nastaven příznak (opět s Java zde). Když ochrana tam není vždy, není to velmi užitečná funkce.

Existuje myšlenková škola, která říká, že pokud něco „prosazujete“, můžete také napsat smysluplný blok if/throw. Tento myšlenkový proces vychází z mnoha tvrzení umístěných na začátku metody, aby se zajistilo, že všechny hodnoty jsou v mezích. Testování vašich předpokladů je velmi důležitou součástí očekávaného postcondition.

Testování jednotky je zvláštní kód, který musí být napsán a udržován. Pro mnohé je to nevýhoda. Avšak s aktuálním rámcem jednotkových testovacích rámců tam můžete vygenerovat větší počet testovacích podmínek s relativně malým kódem. Parametrizované testy a „teorie“ provedou stejný test s velkým počtem vzorků dat, které mohou odhalit některé obtížně vyhledatelné chyby.

Osobně zjišťuji, že jsem s testováním jednotek dosáhl více ujetých kilometrů, než proplétající se tvrzení, ale je to kvůli platformám, které jsem vyvíjel na většinu času (Java/C #). Jiné jazyky mají robustnější podporu prohlašování a dokonce i „Design by Contract“ (viz níže), aby poskytovaly ještě více záruk. Kdybych pracoval s jedním z těchto jazyků, mohl bych použít DBC více než testování jednotek.

http://en.wikipedia.org/wiki/Design_by_contract#Languages_with_native_support

5
Berin Loritsch