Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 3 - Testování ve VB.NET - Dokončení unit testů a best practices

V minulé lekci, Testování ve VB.NET - Úvod do unit testů a příprava projektu, jsme si připravili jednoduchou třídu a vygenerovali testovací projekt s potřebnou referencí.

V dnešním tutoriálu Testování ve VB .NET pokryjeme testy naši jednoduchou třídu. Uvedeme si dostupné asserční metody a unit testy ve VB .NET dovršíme přehledem best practices.

Jednotlivé metody budeme vždy označovat atributem <TestMethod>. Zajistíme tím, že se bude testovat jedna konkrétní metoda z třídy Kalkulacka. Typicky pro několik různých vstupů.

Metody označujeme atributy. Umožňuje nám to vytvořit si i pomocné metody, které můžeme v daném testu využívat. Nebudou pokládány za testy. Visual Studio nám totiž testy (metody s anotací <TestMethod>) automaticky spustí a vypíše jejich výsledky.

Metody třídy KalkulackaTests

Do našeho projektu (do třídy KalkulackaTests) přidáme pod metodu Cleanup() pět následujících metod:

<TestMethod>
Public Sub Secti()
    Assert.AreEqual(2, CInt(kalkulacka.Secti(1, 1)))
    Assert.AreEqual(1.42, kalkulacka.Secti(3.14, -1.72), 0.001)
    Assert.AreEqual(2.0 / 3, kalkulacka.Secti(1.0 / 3, 1.0 / 3), 0.001)
End Sub

<TestMethod>
Public Sub Odecti()
    Assert.AreEqual(0, CInt(kalkulacka.Odecti(1, 1)))
    Assert.AreEqual(4.86, kalkulacka.Odecti(3.14, -1.72), 0.001)
    Assert.AreEqual(2.0 / 3, kalkulacka.Odecti(1.0 / 3, -1.0 / 3), 0.001)
End Sub

<TestMethod>
Public Sub Vynasob()
    Assert.AreEqual(2, CInt(kalkulacka.Vynasob(1, 2)))
    Assert.AreEqual(-5.4008, kalkulacka.Vynasob(3.14, -1.72), 0.001)
    Assert.AreEqual(0.111, kalkulacka.Vynasob(1.0 / 3, 1.0 / 3), 0.001)
End Sub

<TestMethod>
Public Sub Vydel()
    Assert.AreEqual(2, CInt(kalkulacka.Vydel(4, 2)))
    Assert.AreEqual(-1.826, kalkulacka.Vydel(3.14, -1.72), 0.001)
    Assert.AreEqual(1, CInt(kalkulacka.Vydel(1.0 / 3, 1.0 / 3)))
End Sub

<TestMethod>
<ExpectedException(GetType(ArgumentException))>
Public Sub VydelVyjimka()
    kalkulacka.Vydel(2, 0)
End Sub

K porovnávání výstupu metody s očekávanou hodnotou používáme statické metody na třídě Assert. Nejčastěji používáme metodu AreEqual() přijímající v prvním parametru očekávanou hodnotu a v druhém parametru hodnotu aktuální.

Pořadí parametrů je dobré dodržovat, jinak budeme mít hodnoty ve výsledcích testů opačně.

Desetinná čísla jsou v paměti počítače reprezentována binárně (jak jinak :) ). To způsobí určitou ztrátu jejich přesnosti, a také určité obtíže při jejich porovnávání. Proto musíme v tomto případě zadat i třetí parametr. Tímto parametrem je delta, tedy kladná tolerance. O kolik se může očekávaná a aktuální hodnota lišit, aby test stále prošel.

Zkoušíme různé vstupy. Sčítání netestujeme jen jako 1 + 1 = 2. Zkoušíme celočíselné, desetinné i negativní vstupy. Vše odděleně s ověřením výsledků. V některých případech by nás mohla zajímat také maximální hodnota datových typů a podobně.

Poslední test ověřuje, zda metoda Vydel() opravdu vyvolá výjimku při nulovém děliteli. Nemusíme se zatěžovat s try-catch bloky. Stačí nad metodu přidat atribut <ExpectedException>. Uvést zde typ výjimky, která se očekává. Pokud výjimka nenastane, test selže. Pro testování více případů vyvolání výjimky můžeme použít další assert metody, viz níže.

Dostupné Assert metody

Bylo by vhodné zmínit, že se porovnává s ohledem na datové typy. Tedy 10L (long) je jiná hodnota, než 10 (int). Kromě metody AreEqual() můžeme použít ještě mnoho dalších. Snažíme se použít tu nejvíce vyhovující metodu. To totiž zpřehledňuje hlášky při selhání testů a samozřejmě i následnou opravu.

Uveďme si některé dostupné Assert metody:

  • AreNotEqual() - Používáme pokud chceme ověřit, že se 2 objekty NEshodují. Další metody s Not zde již nebudeme zbytečně zmiňovat.
  • AreSame() - Zkontroluje zda 2 reference ukazují na stejný objekt (porovnává pomocí operátoru ==).
  • Equals() - Používáme v případě, pokud chceme ověřit 2 objekty pomocí metody Equals() a zjistit, jestli jsou stejné. Nepoužíváme pro ověření hodnoty místo AreEqual().
  • Fail() - Způsobí selhání testů. Obvykle ji vkládáme za nějakou podmínku. Doplňujeme o volitelné parametry (chybová hláška a parametry).
  • Inconclusive() - Funguje podobně jako Fail(). Vyvolá výjimku signalizující neprůkaznost testu.
  • IsFalse() - Ověří, zda je daný výraz NEpravdivý.
  • IsInstanceOfType() - Ověří, zda je objekt instancí daného typu.
  • IsNull() - Ověří, zda je hodnota null.
  • IsTrue() - Ověří, zda je daný výraz pravdivý.
  • ReplaceNullChars() - Nahradí nulové znaky \0 za \\0. Využijeme zejména u diagnostických výpisů řetězců s těmito znaky.
  • ThrowsException() - Spustí předaný delegát a ověří, že vyvolává výjimku předanou jako generický argument. Metoda má také asynchronní verzi ThrowsExceptionAsync().

Nenechme se zmást metodou ReferenceEquals(). Není součástí testů, ale je standardně na všech třídách.

Spuštění testů

Testy spustíme z menu Test -> Run All Tests:

Testování ve VB.NET

Uvidíme výsledky, které vypadají takto:

testkalk_vysledek_testu - Testování ve VB.NET

Zkusme si nyní udělat v kalkulačce chybu. Např. zakomentujme vyvolávání výjimky při dělení nulou a vraťme vždy hodnotu 1:

Public Function Vydel(a As Double, b As Double) As Double
    'If b = 0 Then
    'Throw New ArgumentException("Nulou nelze dělit!")
    'End If
    Return 1
End Function

A spusťme znovu naše testy:

testkalk_vysledek_s_vadou - Testování ve VB.NET

Vidíme, že chyba je zachycena. Jsme na ni upozorněni. Neprošel jak test dělení, tak test vyvolání výjimky. Můžeme kód vrátit zpět do původního stavu.

Best practices

Best practices jsme již nakousli. Toto je k unit testům ve VB .NET vše. Pojďme si na závěr vyjmenovat jakých častých chyb se vyvarovat, abychom dosáhli kvalitního výsledku.

Best practices probíráme detailněji v kurzu Best practices pro návrh softwaru.

Specifikace testů

Testy nikdy nepíšeme podle kódu nějaké metody. Zamýšlíme se nad tím, k čemu metoda reálně slouží. Také nad tím, co vše ji může přijít jako vstup.

Testování obecných knihoven

Netestujeme konkrétní logiku aplikace. Pokud je logika důležitá a obecná, měla by být vyčleněná do samostatné knihovny. Ta by měla být poté testována.

Nezávislost testů

Každý test by měl být úplně nezávislý na ostatních testech. Scénář by měl proběhnout i když metody libovolně proházíme. Žádná metoda by po sobě neměla zanechávat nějaké změny (v souborech, v databázi a podobně), které by ovlivnily další metody. K dosažení tohoto chování často připravujeme prostředí pro jednotlivé metody v inicializační metodě. Případně po nich ještě provedeme úklid v metodě úklidové. To samé platí i pro celé testy.

Stabilita testů

Každý test by měl dopadnout vždy stejně. Bez ohledu na to, kdy jej spustíme. Pozor na testování generátorů náhodných výstupů a na práci s datem a časem.

Duplicitní porovnání

Pokud nějaký vstup již ověřuje jiný test, neprovádějme toto ověření znovu.

Jednotkové testy a návrh software

Náš software by měl být navržený tak, aby byl rozdělený na menší třídy. Ty mají minimální závislosti na ostatních. Proto se dají jednoduše a nezávisle testovat (vzory high cohesion a low coupling).

Externí služby

Měli bychom je tzv. mockovat. Tím vytváříme "falešné" služby se stejným rozhraním, které obvykle jen podstrkují testovací data. Využitím skutečných služeb bychom porušili nezávislost testů, jelikož by se navzájem začaly ovlivňovat. Méně elegantní řešení je, vždy na začátku nastavit a na konci vrátit stav služeb.

Názvy testů

Vyhněme se zavádějícím názvům testů (jako vypocet(), vyjimka() a podobně). Programátoři často pojmenovávají testy i větším počtem slov, aby se poznalo, co dělají. Běžně bychom to u metod neměli dělat, jelikož každá metoda dělá jen jednu činnost. Někdy u testů dává smysl pojmenovat metody např. i takto obskurně KvadratickaRovnice_ZaporneKoeficienty_Vyjimka(). Test často testuje více vstupů. Ideálně by měl název testu obsahovat název metody, kterou testuje. V pojmenovávání testů bychom měli být konzistentní. Nebojme se ani komentářů.

Rychlost testů

V praxi obvykle testujeme všechny části aplikace různými typy testů a všechny časy se dokáží nasčítat do nepříjemné pauzy.

Naše první unit testy nemusí být perfektní. Stačí krátce otestovat to nejdůležitější. Časem se začnou odhalovat chyby v implementaci. Čím je aplikace větší, tím o větší pokrytí testy (test code coverage) bychom se měli snažit.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 3x (2.17 MB)
Aplikace je včetně zdrojových kódů v jazyce VB.NET

 

Předchozí článek
Testování ve VB.NET - Úvod do unit testů a příprava projektu
Všechny články v sekci
Testování ve VB.NET
Článek pro vás napsal Stanislav Zita
Avatar
Uživatelské hodnocení:
1 hlasů
Aktivity