2. díl - Testování v C# .NET - Úvod do unit testů a příprava projektu

C# .NET Testování Testování v C# .NET - Úvod do unit testů a příprava projektu

ONEbit hosting Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V minulé lekci online kurzu o testování softwaru v C# .NET jsme si udělali poměrně solidní úvod do problematiky. Také jsme si uvedli v-model, který znázorňuje vztah mezi jednotlivými výstupy fází návrhu a příslušnými testy.

Testy tedy píšeme vždy na základě návrhu, nikoli implementace. Jinými slovy, děláme je na základě očekávané funkčnosti. Ta může být buď přímo od zákazníka (a to v případě akceptačních testů) nebo již od programátora (architekta), kde specifikuje jak se má která metoda chovat. Dnes se budeme věnovat právě těmto testům, kterým říkáme jednotkové (unit testy) a které testují detailní specifikaci aplikace, tedy její třídy.

Pamatujte, že nikdy nepíšeme testy podle toho, jak je něco uvnitř naprogramované! Velmi jednoduše by to mohlo naše myšlení svést jen tím daným způsobem a zapomněli bychom na to, že metodě mohou přijít třeba i jiné vstupy, na které není vůbec připravená. Testování s implementací ve skutečnosti vůbec nesouvisí, vždy testujeme zda je splněno zadání.

Jaké třídy testujeme

Unit testy testují jednotlivé metody ve třídách. Pro jistotu zopakuji, že nemá valný smysl testovat jednoúčelové metody např. v modelech, které např. pouze něco vybírají z databáze. Abychom byli konkrétnější, nemá smysl testovat metodu jako je tato:

public void VlozPolozku(string nazev, double cena)
{
        using (var db = new DatabaseEntities())
        {
                db.polozky.Add(new Polozka(nazev, cena));
                db.SaveChanges();
        }
}

Metoda přidává položku do databáze. Typicky je použita jen v nějakém formuláři a pokud by nefungovala, zjistí to akceptační testy, jelikož by se nová položka neobjevila v seznamu. Podobných metod je v aplikaci hodně a zbytečně bychom ztráceli čas pokrýváním něčeho, co snadno pokryjeme v jiných testech.

Unit testy nalezneme nejčastěji u knihoven, tedy nástrojů, které programátor používá na více místech nebo dokonce ve více projektech a měly by být 100% funkční. Možná si vzpomenete, kdy jste použili nějakou knihovnu, staženou např. z GitHubu. Velmi pravděpodobně u ní byly také testy. Pokud např. píšeme aplikaci, ve které často potřebujeme nějaké matematické výpočty, např. faktoriály a další pravděpodobnostní funkce, je samozřejmostí vytvořit si na tyto výpočty knihovnu a je velmi dobrý nápad pokrýt takovou knihovnu testy.

Příklad

Jak asi tušíte, my si podobnou třídu vytvoříme a zkusíme si ji otestovat. Abychom se nezdržovali, vytvořme si pouze jednoduchou kalkulačku, která bude umět:

  • sčítat
  • odčítat
  • násobit
  • dělit

Vytvoření projektu

V praxi by ve třídě byly nějaké složitější výpočty, ale tím se zde zabývat nebudeme. Vytvořte si nový projekt, konzolovou aplikaci, s názvem KalkulackaApp. Do něj si přidejte veřejnou (public) třídu Kalkulacka a následující implementací:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace KalkulackaApp
{
        /// <summary>
        /// Reprezentuje jednoduchou kalkulačku
        /// </summary>
        public class Kalkulacka
        {

                /// <summary>
                /// Sečte 2 čísla
                /// </summary>
                /// <param name="a">První číslo</param>
                /// <param name="b">Druhé číslo</param>
                /// <returns>Součet 2 čísel</returns>
                public double Secti(double a, double b)
                {
                        return a + b;
                }

                /// <summary>
                /// Odečte 2 čísla
                /// </summary>
                /// <param name="a">První číslo</param>
                /// <param name="b">Druhé číslo</param>
                /// <returns>Rozdíl 2 čísel</returns>
                public double Odecti(double a, double b)
                {
                        return a - b;
                }

                /// <summary>
                /// Vynásobí 2 čísla
                /// </summary>
                /// <param name="a">První číslo</param>
                /// <param name="b">Druhé číslo</param>
                /// <returns>Součin 2 čísel</returns>
                public double Vynasob(double a, double b)
                {
                        return a * b;
                }

                /// <summary>
                /// Vydělí 2 čísla
                /// </summary>
                /// <param name="a">První číslo</param>
                /// <param name="b">Druhé číslo</param>
                /// <returns>Podíl 2 čísel</returns>
                public double Vydel(double a, double b)
                {
                        if (b == 0)
                                throw new ArgumentException("Nulou nelze dělit!");
                        return a / b;
                }

        }
}

Na kódu je zajímavá pouze metoda Vydel(), která vyvolá výjimku v případě, že dělíme nulou. Výchozí chování C# .NET pro desetinná čísla je vrácení hodnoty "Infinity", což není vždy to, co uživatel aplikace očekává.

UnitTesting

V C# .NET se unit testy píší pomocí nástrojů ve jmenném prostoru Microsoft.Visu­alStudio.TestTo­ols.UnitTestin­g. Visual Studio poskytuje plnou podporu těchto testů a ke své aplikaci je přidáme jako další projekt do solution. Testy tedy budou od projektu úplně oddělené, což je návrhově velká výhoda, pouze nesmíme zapomenou projekty propojit příslušnými referencemi.

V Solution Exploreru klikneme na solution "KalkulackaApp" pravým tlačítkem a zvolíme Add -> New Project....

Přidání nového testovacího projektu ve Visual Studio

Název projektu s testy se zpravidla sestavuje jako název projektu aplikace + slovo "Tests", v našem případě tedy "KalkulackaAp­pTests".

Testovací projekt pro C# .NET

Do testovacího projektu nyní musíme přidat referenci na projekt s aplikací, abychom mohli přistupovat k příslušným třídám. To provedeme kliknutím pravým tlačítkem na projekt KalkulackaAppTests a zvolením Add -> Reference...

Přidání reference na projekt při testování v C# .NET

V následujícím formuláři vybereme záložku Projects -> Solution a zaškrtneme projekt KalkulackaApp. Dialog potvrdíme a tím si zpřístupníme třídu Kalkulacka.

Přidání reference na projekt při testování v C# .NET

V projektu KalkulackaAppTest se nám vygeneroval nový soubor UnitTest1 s následujícím kódem:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace KalkulackaAppTests
{
        [TestClass]
        public class UnitTest1
        {
                [TestMethod]
                public void TestMethod1()
                {
                }
        }
}

Asi vás v objektovém C# nepřekvapí, že je test třídy (scénář) reprezentovaný také třídou a jednotlivé testy metodami :) S atributy (hranatými závorkami nad metodami a třídami) jsme se již v seriálu setkali a víme, že slouží k dospecifikování nějakých informací. [TestClass] zde označuje testovací scénář, pomocí [TestMethod] jsou označené metody, které reprezentují jednotlivé testy (budou automaticky spouštěné Visual Studiem). Třídu (i její soubor) si přejmenujte na "KalkulackaTests", jelikož bude obsahovat testy pro třídu Kalkulacka.

Pokrytí třídy testy

V unit testech můžeme použít ještě několik atributů. My nyní využijeme [TestInitialize] a pro názornost i [TestCleanup], čímž můžeme označit metody, které se zavolají před, resp. po každém testu v této třídě. To je pro nás velmi důležité, jelikož podle best practices chceme, aby byly testy nezávislé. Obvykle tedy před každým testem připravujeme znovu to samé prostředí, aby se vzájemně vůbec neovlivňovaly. O dobrých praktikách se zmíníme detailněji později. Do třídy si přidejme field (atribut třídy v názvosloví OOP) kalkulacka a v metodě s anotací [TestInitialize] v něm vždy vytvořme čerstvě novou kalkulačku pro každý test. Pokud by ji bylo ještě třeba dále nastavovat nebo bylo třeba vytvořit další závislosti, byly by také v této metodě. Metodu TestMethod1() odstraníme. Pro kalkulačku přidáme using KalkulackaApp;:

using System;
using KalkulackaApp;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace KalkulackaAppTests
{
        [TestClass]
        public class KalkulackaTests
        {
                private Kalkulacka kalkulacka;

                [TestInitialize]
                public void Initialize()
                {
                        kalkulacka = new Kalkulacka(); // Vytvoří novou kalkulačku před každým testem
                }

                [TestCleanup]
                public void Cleanup()
                {
                }

}

Máme vše připraveno k přidávání samotných testů, což uděláme v příští lekci.


 

 

Článek pro vás napsal David Čápka
Avatar
Jak se ti líbí článek?
Ještě nikdo nehodnotil, buď první!
Autor pracuje jako softwarový architekt a pedagog na projektu ITnetwork.cz (a jeho zahraničních verzích). Velmi si váží svobody podnikání v naší zemi a věří, že když se člověk neštítí práce, tak dokáže úplně cokoli.
Unicorn College Autor se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity (1)

 

 

Komentáře

Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zatím nikdo nevložil komentář - buď první!