Postupy: Vytváření a spouštění testování částí pro spravovaný kód
Tento návod vás postupně provede vytvářením, spuštěním a přizpůsobením série jednotkových testů pomocí rámce jednotkových testů spravovaného kódu společnosti Microsoft a Průzkumníkem testů systému Visual Studio.Nejprve začnete s projektem v jazyce C#, který je ve vývoji, vytvoříte testy, které testují jeho kód, tyto testy spustíte a prozkoumáte jejich výsledky.Potom můžete změnit kód projektu a znovu spustit testy.
Toto téma obsahuje následující oddíly:
Vytvoření projektu jednotkového testu
Vytvoření první testovací metody
Oprava kódu a opětovné spuštění testů
Použití jednotkových testů ke zlepšení kódu
[!POZNÁMKA]
Tento návod používá rámec jednotkových testů spravovaného kódu společnosti Microsoft.Průzkumník testů může také spouštět testy rámců jednotkových testů třetích stran, které mají adaptéry pro Průzkumník testů.Další informace naleznete v tématu Jak: instalace rámce Test jednotek výrobců
[!POZNÁMKA]
Více informací o spuštění testů z příkazového řádku naleznete v Názorný postup: Pomocí nástroje příkazového řádku Test.
Požadavky
- Projekt banky.Viz téma Ukázkový projekt testování částí.
Příprava prostředí
K přípravě prostředí proveďte následující
Otevřete Visual Studio 2012.
V nabídce Soubor přejděte na příkaz Nový a klikněte na Projekt.
Zobrazí se dialogové okno Nový projekt.
V položce Nainstalované šablony klikněte na položku Visual C#.
V seznamu typů aplikací klikněte na položku Knihovna tříd.
Do pole Název zadejte hodnotu Bank a pak klikněte na tlačítko OK.
[!POZNÁMKA]
Pokud je již název "Bank" používán, zvolte jiný název projektu.
Nový projekt Bank je vytvoření a zobrazen v Průzkumníku řešení a jeho soubor Class1.cs je otevřen v Editoru kódu.
[!POZNÁMKA]
Pokud není v Editoru kódu otevřen soubor Class1.cs, otevřete jej dvojitým kliknutím na tento soubor v Průzkumníku řešení.
Zkopírujte zdrojový kód z Ukázkový projekt testování částí.
Nahraďte původní obsah souboru Class1.cs kódem z Ukázkový projekt testování částí.
Uložte soubor jako BankAccount.cs
V nabídce Sestavení klikněte na příkaz Sestavit řešení.
Nyní jste vytvořili projekt s názvem Bank.Obsahuje zdrojový kód pro testování a nástroje, pomocí kterých jej bude možné otestovat.Obor názvů BankAccountNS pro projekt Bank obsahuje veřejnou třídu BankAccount, jejíž metody budete v následujícím postupu testovat.
Toto rychlé seznámení se zaměří na metodu Debit. Tato metoda je volána, když jsou peníze vybrány z účtu a obsahuje následující kód:
// method under test
public void Debit(double amount)
{
if(amount > m_balance)
{
throw new ArgumentOutOfRangeException("amount");
}
if (amount < 0)
{
throw new ArgumentOutOfRangeException("amount");
}
m_balance += amount;
}
Vytvoření projektu jednotkového testu
Požadavky: Postupujte podle postupu uvedeném v sekci Příprava prostředí.
Vytvoření projektu jednotkového testu
V nabídce Soubor klikněte na položku Přidat a poté na položku Nový projekt ....
V dialogovém okně Nový projekt rozbalte položku Nainstalované, poté rozbalte položku **Visual C#**a nakonec zvolte položku Test.
Ze seznamu šablon vyberte položku Projekt jednotkového testu.
Do pole Název zadejte hodnotu BankTest a potom zvolte OK.
Projekt BankTests se přidá do řešení Bank.
Do projektu BankTests přidejte odkaz na řešení Bank.
V Průzkumníku řešení vyberte položku Odkazy v projektu BankTests a poté zvolte položku Přidat odkaz z kontextové nabídky.
V dialogovém okně Správce odkazů rozbalte položku Řešení a zaškrtněte pole Bank.
Vytvoření testovací třídy
Nejprve je potřeba vytvořit testovací třídu pro ověření třídy BankAccount.Je možné použít třídu UnitTest1.cs vygenerovanou z šablony projektu, ale je vhodné dát souboru a třídě více popisné názvy.To je možné udělat v jednom kroku přejmenováním souboru v Průzkumníku řešení.
Přejmenování souboru třídy
V Průzkumníku řešení zvolte soubor UnitTest1.cs v projektu BankTests.Z kontextové nabídky zvolte položku Přejmenovata potom přejmenujte soubor na BankAccountTests.cs.Ve zobrazeném dialogovém okně s dotazem na přejmenování všech odkazů v projektu na prvek kódu "UnitTest1" zvolte Ano.Tento krok změní název třídy na BankAccountTest.
Soubor BankAccountTests.cs nyní obsahuje následující kód:
// unit test code
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace BankTests
{
[TestClass]
public class BankAccountTests
{
[TestMethod]
public void TestMethod1()
{
}
}
}
Přidání příkazu using, který bude odkazovat na testovaný projekt
Je také možné přidat příkaz using přímo na testovanou třídu, aby bylo možné volat testovaný projekt přímo bez nutnosti použití plně kvalifikovaných názvů.Na začátek souboru třídy přidejte:
using BankAccountNS
Požadavky na testovací třídu
Minimální požadavky na testovací třídu jsou následující:
Atribut [TestClass] je vyžadován pro všechny třídy v rámci jednotkových testů pro spravovaný kód společnosti Microsoft, které obsahují metody jednotkového testu spouštěné v Průzkumníku testů.
Musí mít každý zkušební metody, který chcete spustit aplikace Explorer otestovat [TestMethod]atribut.
Máte další třídy v projektu test jednotky, které nemají [TestClass] atribut který může mít jiné metody test tříd, které nemají [TestMethod] atribut.Ve zkušební metody mohou pomocí těchto tříd a metod.
Vytvoření první testovací metody
V tomto postupu vytvoříte metody jednotkového testu, které ověří chování metody Debit ve třídě BankAccount.Tato metoda je uvedena výše.
Analýzou testované metody zjistíte, že metoda obsahuje alespoň tři typy chování, které je třeba zkontrolovat:
Metoda vyvolá výjimku [ArgumentOutOfRangeException], pokud je požadovaná částka větší než zůstatek na účtu.
Také vyvolá výjimku ArgumentOutOfRangeException, pokud je požadovaná částka menší než nula.
Pokud jsou kontroly v bodech 1.) a 2.) splněny, metoda odečte požadovanou částku od zůstatku účtu.
V prvním testu ověříte, že platná částka (která je menší než zůstatek a přitom větší než nula) odečte správnou hodnotu z účtu.
Vytvoření testovací metody
Přidejte příkaz using BankAccountNS; do souboru BankAccountTests.cs.
Přidejte do této třídy BankAccountTests následující metodu:
// unit test code [TestMethod] public void Debit_WithValidAmount_UpdatesBalance() { // arrange double beginningBalance = 11.99; double debitAmount = 4.55; double expected = 7.44; BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance); // act account.Debit(debitAmount); // assert double actual = account.Balance; Assert.AreEqual(expected, actual, 0.001, "Account not debited correctly"); }
Tato metoda je velmi jednoduchá.Nejprve vytvoří nový objekt BankAccount s počátečním zůstatkem a potom z něj vybere platnou částku.Pro ověření očekávané hodnoty výsledného zůstatku na účtu je použita metoda rámce jednotkových testů pro spravovaný kód společnosti Microsoft AreEqual.
Požadavky na testovací metodu
Testovací metoda musí splňovat následující požadavky:
Metoda musí být označena atributem [TestMethod].
Metoda musí vracet typ void.
Metoda nemůže obsahovat parametry.
Vytvoření a spuštění testu
Sestavení a spuštění testu
V nabídce Sestavení vyberte položku Sestavení řešení.
Pokud test neodhalí žádné chyby, zobrazí se okno UnitTestExplorer, v němž je metoda Debit_WithValidAmount_UpdatesBalance uvedena ve skupině Nespuštěné testy.Pokud se po úspěšném sestavení nezobrazí Průzkumník testů, zvolte nabídku Test a poté zvolte položku Okna, kde zvolte položku Průzkumník testů.
Pro spuštění všech testů zvolte položku Spustit všechny.Dokud testy probíhají, je stavový řádek v horní části okna animovaný.Na konci testovacího běhu stavový řádek zezelená, pokud všechny testovací metody proběhly úspěšně, nebo zčervená, pokud některé testy selhaly.
V tomto případě test selhal.Testovací metoda je přesunuta do skupiny Neúspěšné testy.Pro zobrazení detailů o metodě, zvolte tuto metodu ve spodní části okna Průzkumníka testů.
Oprava kódu a opětovné spuštění testů
Analýza výsledků testování
Výsledek testu obsahuje zprávu s popisem chyby.Pro metodu AreEquals zobrazuje zpráva očekávanou hodnotu (parametr Expected<XXX>) a skutečnou hodnotu (parametr Actual<YYY>).Očekávalo se snížení zůstatku, ale namísto toho byl zůstatek navýšen o požadovanou hodnotu výběru.
Přezkoumání kódu metody Debit ukazuje, že jednotkový test úspěšně nalezl chybu.Požadovaná částka výběru je přičtena k zůstatku namísto toho, aby od něj byla odečtena.
Oprava chyby
Chybu jednoduše opravíte tím, že nahradíte řádek
m_balance += amount;
tímto kódem:
m_balance -= amount;
Opětovné provedení testu
Pro opětovné provedení všech testů zvolte v Průzkumníku testů položku Spustit všechny.Barva červeno/zeleného stavového řádku se změní na zelenou a test je přesunut do skupiny Úspěšné testy.
Použití jednotkových testů ke zlepšení kódu
Tato sekce popisuje, jak může iterativní proces analýzy, vývoj jednotkových testů a refaktoring kódu pomoci při vytváření robustnějšího a efektivnějšího produkčního kódu.
Analýza problémů
Po vytvoření testovací metody pro potvrzení správného odečtení platné částky v metodě Debit je potřeba se zabývat zbývajícími případy, které byly odhaleny původní analýzou:
Metoda vyvolá výjimku ArgumentOutOfRangeException, pokud je požadovaná částka větší než zůstatek na účtu.
Také vyvolá výjimku ArgumentOutOfRangeException, pokud je požadovaná částka menší než nula.
Vytvoření testovacích metod
První pokus o vytvoření testovací metody, která bude ověřovat tyto problémy, vypadá slibně:
//unit test method
[TestMethod]
[ExpectedException(typeof(ArgumentOutOfRangeException))]
public void Debit_WhenAmountIsLessThanZero_ShouldThrowArgumentOutOfRange()
{
// arrange
double beginningBalance = 11.99;
double debitAmount = -100.00;
BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance);
// act
account.Debit(debitAmount);
// assert is handled by ExpectedException
}
Atribut ExpectedExceptionAttribute se používá k vyhodnocení, že byla vyvolána požadovaná výjimka.Atribut způsobí selhání testu, pokud není vyvolána výjimka ArgumentOutOfRangeException.Spuštěním testu s kladnými i zápornými hodnotami parametry debitAmount a následná dočasná změna testované metody, aby při zadání záporné hodnoty vyvolala obecnou výjimku ApplicationException, prokazuje správné chování testu.K otestování případu, kdy vybíraná hodnota je vyšší než zůstatek na účtu, stačí provést následující:
Vytvořit novou testovací metodu s názvem Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange.
Zkopírovat tělo metody Debit_WhenAmountIsLessThanZero_ShouldThrowArgumentOutOfRange do této nové metody.
Nastavit hodnotu parametru debitAmount na číslo větší než zůstatek.
Spuštění testů
Spuštění těchto dvou metod s různými hodnotami parametru debitAmount ukazuje, že testy vhodně ověřují zbývající případy.Spuštění všech tří testů potvrzuje, že všechny případy původní analýzy jsou správně pokryty.
Pokračování analýzy
Dvě poslední metody jsou však poněkud zneklidňující.Není možné si být jistý, která podmínka testovaného kódu byla vyvolána při provádění těchto testů.Nějaký způsob odlišení těchto dvou podmínek by mohl být užitečný.Při hlubším zamyšlení je zřejmé, že možnost odlišení těchto podmínek by zvýšilo důvěru v tyto testy.Tato informace by také mohla pravděpodobně být užitečná i pro produkční mechanismus, který zpracovává výjimku vyvolanou testovanou metodou.Generování dalších informací při vyvolání výjimky testovanou metodou by pomohlo všem zúčastněným, ale atribut ExpectedException nedokáže s takovou informací pracovat.
Přezkoumání testované metody ukáže, že oba podmíněné příkazy používají konstruktor výjimky ArgumentOutOfRangeException, který jako parametr přebírá název argumentu:
throw new ArgumentOutOfRangeException("amount");
Vyhledáváním v knihovně MSDN je možné zjistit, že pro tuto výjimku existuje i konstruktor poskytující bohatší informace.Konstruktor ArgumentOutOfRangeException(String, Object, String) obsahuje název argumentu, hodnotu argumentu a uživatelsky definovanou zprávu.Je tak možné provést refaktoring testované metody, aby používala tento konstruktor.Navíc je možné použít veřejně dostupné členy typů ke specifikaci chyb.
Refaktoring testovaného kódu
Nejprve definujte dvě konstanty pro chybové zprávy na úrovni třídy:
// class under test
public const string DebitAmountExceedsBalanceMessage = "Debit amount exceeds balance";
public const string DebitAmountLessThanZeroMessage = "Debit amount less than zero";
Poté upravte dva podmíněné příkazy v metodě Debit:
// method under test
// ...
if (amount > m_balance)
{
throw new ArgumentOutOfRangeException("amount", amount, DebitAmountExceedsBalanceMessage);
}
if (amount < 0)
{
throw new ArgumentOutOfRangeException("amount", amount, DebitAmountLessThanZeroMessage);
}
// ...
Refaktoring testovacích metod
V testovací metodě nejprve odeberte atribut ExpectedException.Místo něj zachyťte vyvolanou výjimku a ověřte, že byla vyvolána ve správném podmíněném příkazu.Nyní se však musíte rozhodnout mezi dvěma možnostmi, jak ověřit zbývající podmínky.Například pro metodu Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange můžete provést jednu z následujících akcí:
Vyhodnotit, že je vlastnost ActualValue výjimky (druhý parametr konstruktoru ArgumentOutOfRangeException) větší než počáteční zůstatek.Tato možnost vyžaduje otestování vlastnosti ActualValue výjimky proti proměnné beginningBalance testovací metody a také ověření, že je hodnota vlastnosti ActualValue větší než nula.
Vyhodnotit, že zpráva (třetí parametr konstruktoru) obsahuje hodnotu DebitAmountExceedsBalanceMessage definovanou v třídě BankAccount.
Metoda StringAssert.Contains rámce jednotkových testů společnosti Microsoft umožňuje ověřit druhou možnost bez nutnosti výpočtů potřebných v řešení první možnosti.
Druhý pokus revize metody Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange tak může vypadat následovně:
[TestMethod]
public void Debit_WhenAmountIsGreaterThanBalance_ShouldThrowArgumentOutOfRange()
{
// arrange
double beginningBalance = 11.99;
double debitAmount = 20.0;
BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance);\
// act
try
{
account.Debit(debitAmount);
}
catch (ArgumentOutOfRangeException e)
{
// assert
StringAssert.Contains(e.Message, BankAccount. DebitAmountExceedsBalanceMessage);
}
}
Opětovné testování, revize a analýza
Při opakovaném testování testovacích metod s jinými hodnotami můžete dojít k následujícím skutečnostem:
Při zachycení správné chyby pro hodnotu debitAmount větší než zůstatek projde vyhodnocení Contains úspěšně, výjimka bude ignorována a testovací metoda skončí úspěchem.To je požadované chování.
Při použití debitAmount se vyhodnocení nezdaří, protože je vrácena nesprávná chybová zpráva.Vyhodnocení také selže, pokud je zavedena dočasná výjimka ArgumentOutOfRange na jiném místě testované metody.Toto chování je také požadované.
Pokud debitAmount hodnota je platná (tj, méně než zůstatek, ale větší než nula, žádná výjimka uvízl, takže nikdy vyhodnocení uvízl.Testovací metoda skončí úspěchem.To ovšem není vhodné, protože by testovací metoda měla skončit neúspěchem, pokud není vyvolána žádná výjimka.
Třetí fakt je chybou v testovací metodě.Pro vyřešení tohoto problému je potřeba na konec testovací metody přidat vyhodnocení Fail pro zohlednění případu, kdy není vyvolána žádná výjimka.
Opakované spuštění testu však ukáže, že test s touto úpravou selže i pokud došlo k zachycení správné výjimky.Příkaz catch zruší vyvolanou výjimku a metoda tak pokračuje ve svém provádění, což způsobí selhání nově přidaného vyhodnocení.Přidání příkazu return za vyhodnocení StringAssert vyřeší tento problém.Opakované otestování potvrzuje vyřešení všech problémů.Konečné verze metody Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange vypadá následovně:
[TestMethod]
public void Debit_WhenAmountIsGreaterThanBalance_ShouldThrowArgumentOutOfRange()
{
// arrange
double beginningBalance = 11.99;
double debitAmount = 20.0;
BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance);\
// act
try
{
account.Debit(debitAmount);
}
catch (ArgumentOutOfRangeException e)
{
// assert
StringAssert.Contains(e.Message, BankAccount. DebitAmountExceedsBalanceMessage);
return;
}
Assert.Fail("No exception was thrown.")
}
V této závěrečné sekci vedlo vylepšení testovacího kódu k robustnějším a informativnějším testovacím metodám.Důležitější je však fakt, že další analýza také vedla k vylepšení kódu testovaného projektu.