Testováním řízený vývoj
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Testováním řízený vývojTestováním řízený vývoj

 

Testováním řízený vývoj

Google       Google       21. 5. 2006       12 370×

V tomto článku vás Doug Seven seznámí s Testováním řízeným vývojem a ukáže, jak používat tuto metodu designu při každodenním programování s použitím Visual Studio 2005 Team System.

Test Driven Development - Testováním řízený vývoj

Test Driven Development (TDD – Testováním řízený vývoj) není nový koncept. Nápad testovat dřív, ještě před psaním kódu, je tu už několik let. V poslední uvolněné verzi vývojářské utility od Microsoftu, Visual Studio 2005 Team System, bylo přidáno několik rysů, které, mimo jiné, zahrnují i nástroje pro testování softwaru. A co to znamená pro nás, vývojáře? Znamená to hlavně zjednodušení naší práce, teď můžeme použít integrovanou testovací jednotku pro Testováním řízený vývoj.

Co je to Testováním řízený vývoj?

Rád přemýšlím na TDD jako na takovýto způsob vytváření software: Nejdříve zdokumentovat požadavky v jazyce, kterému programátor rozumí, a poté napsat kód splňující požadavky. V knize Test-Driven Development: By Example (česky vyšlo: Programování řízené testy; Kent Beck; Grada Publishing) se definuje TDD dvěma jednoduchými pravidly:

  1. Nikdy nenapište ani jeden řádek kódu, aniž byste neměli automatizovaný test, který neprojde.
  2. Eliminujte duplikace

Kentova pravidla a můj pohled na TDD jdou ruku v ruce. Ve většině vývojových cyklech vlastník produktu nebo projektový manažer poskytne sadu požadavků. Typicky jsou to požadavky v dokumentu napsaném ve Wordu a jsou pojmenovány jako specifikace funkčnosti. Dokument ve Wordu je vynikající pro popsání příběhu, ale to, co potřebujeme my, je popsání příběhu projektového manažera do programovacího jazyka – například nové požadavky jsou napsány v C# (nebo ve Visual Basicu). Požadavky jsou napsány v kódu jako test a každý takový test reprezentuje jeden požadavek. Dále, když pak chceme dopsat později funkčnost, musíme se ujistit, že jsme eliminovali jakýkoliv duplicitní kód (kód určité funkčnosti se nachází pouze na jednom místě).

Typy testů

Pokaždé, když začnu mluvit s lidmi o softwarových testech, začnou okamžitě myslet na testy k ujištění, že aplikace pracuje tak, jak má. Toto je zajisté důležité a lze to rozdělit na dvě části:

  • Programátorské testy
  • Automatizovaný test napsaný programátorem zajišťuje, že program je funkční. Funkční kód je napsán, aby pouze prošel testem, nic víc, nic míň. Tyto testy jsou známy jako unit tests (jednotkové testy).
  • Zákazníkovy testy
  • Test napsaný inženýry k validaci (ověření) funkce celé aplikace z pohledu zákazníka. Tyto testy jsou známy jako testy přijatelnosti (acceptance tests).

Po zbývající část tohoto článku budu psát výhradně o programátorských testech, za které, i když mají v názvu slovo „test“, jsou zodpovědní programátoři.

Ani víc, ani míň

V definici programátorských testů jsem zmínil, že funkční kód by neměl dělat víc nebo míň, než co test indikuje. To je mnohem složitější, než jak to vypadá. Je přirozená tendence, speciálně pro programátory, pokoušet se nahlížet do budoucnosti. Kolikrát, zatímco jste psali program, jste museli přidat „funkčnost“, protože jste věděli, že eventuálně by to zákazník mohl požadovat. Například jste dopsali metodu k získání celkového počtu objednávek jednoho zákazníka, a to i přesto, že to nepatřilo do momentální specifikace. Tohle ale už nebude více potřeba.

To je past, které se musíme vyhnout. Albert Einstein jednou řekl: „Každý hlupák může udělat věci většími, více komplexními a více násilnými. Vyžaduje to dotek génia – a hodně odvahy – uvažovat naopak“ (‘Any intelligent fool can make things bigger, more complex, and more violent. It takes a touch of genius -- and a lot of courage -- to move in the opposite direction.’). Jiným slovy, doopravdy skvělý kód obsahuje pouze nezbytný kód k vykonání požadavků a nic víc. Kód funkčnosti by měl projít všemi programátorovými testy, komunikovat jasně a být vytvořen z nejmenšího možného počtu tříd a metod. Když dělá program všechny tyto věci, je hotovo. Odstupte od klávesnice a odolejte pokušení ještě něco přidat.

To je skvělé, ale jak to funguje?

Pokud se jako programátor rozhodnete pro používání TDD, první krok, který musí udělat, je zdokumentovat požadavky funkčnosti jako programové testy. Udělejte to dřív, než napíšete jakýkoliv kód. Začněte vytvořením Seznamu testů. Popište všechny testy, které definují požadavky a ujistěte se, že tento list plně pokrývá soupis požadavků. Ujistěte se, že Seznam testů je maximálně jednoduchý, ale zároveň se ujistěte, že všechny požadavky jsou zdokumentovány.

Například řekněme, že část naší aplikace je vytvoření objektu reprezentujícího Produkt. Seznam testů může vypadat nějak takto:

  1. Vytvoř Product a zkontroluj IsDirty (data v objektu nejsou shodná s údaji uložené v databázi - některá položka objektu byla změněna), jestli je nepravdivý (false).
  2. Vytvoř Product a změn Product Name (název produktu) a zkontroluj IsDirty, jestli je nepravda.
  3. Vytvoř Product, změň Product Name a zkontroluje, zda Product Name byl změněn.
  4. Vytvoř Product a změň Product Name, ulož Product a zkontroluj, zda Product byl uložen.

Toto je zjednodušená verze seznamu testů a záleží na požadavcích, zda nepotřebují být podrobněji rozepsány.

Červený/Zelený/Refaktor

Červený/Zelený/Refaktor je TDD mantra a popisuje tři stavy, kterými procházíme, když píšeme kód při použití TDD metod.

  • Červený
  • Napište test, který selže
  • Zelený
  • Napište kód, který testem projde
  • Refactor
  • Zlepište kód, beze změny funkčnosti

Můžeme říct: „Nechte, aby to selhalo. Nechte, aby to fungovalo. Udělejte to líp“. Podívejme se na tyto kroky při programování.

Psaní programátorových testů

Splňme první požadavek (test) v našem seznamu testů. Ve Visual Studio 2005 Team System (věřím, že máte Developer Edition nebo Test Edition), můžete vytvořit nový druh projektu, a to Test Projekt (Test Project).

Test Project vytváří několik částí a já se hodlám zaměřit na UnitTest1.cs. V tomto souboru budete dokumentovat vaše požadavky v C#. Smažte ManualTest1.mht – nebudeme ho potřebovat.


using System;
using System.Text;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace DotNetJunkiesTDD {

  [TestClass]
  public class ProductTest {

    public ProductTest() {
      // TODO: Add constructor logic here // 
    }

    [TestMethod] 
    public void TestMethod1() {
      // TODO: Add test logic here
    }
  }
}

V předcházejícím bloku kódu vidíte základní strukturu třídy testu. Toto je třída, která je specifická pro obsažení jednotkových (unit) testů. Soubor zahrnuje referenci na jmenný prostor Microsoft.VisualStudio.TestTools.UnitTesting. To nám zpřístupní všechny potřebné třídy a metody pro jednotkové testy do této třídy. Definice třídy je změněna pomocí [TestClass] atributu. Ten určuje třídu jako kolekci jednotkových (unit) testů (pokud jste používali NUnit, toto je ekvivalent pro TestFixture). K deklaraci metody je přidán atribut [TestMethod]. Ten určí tuto metodu jako test pro jednu jednotku funkcionality. Jeden rys (funkčnost) může obsahovat několik programatorských testů. (v NUnit je toto Test).

Červená

K napsání prvního požadavku jako programátorského testu můžete napsat TestMethod1 tak, jak je ukázáno níže:


/// 
/// Vytvoří Product a zkontroluje, jestli je IsDirty pravda.
/// 
[TestMethod]
public void CheckIsDirty() {
  Product prod = new Product();
  Assert.IsTrue(prod.IsDirty);
} 

V předchozím bloku kódu jsme si definovali metodu CheckIsDirty jako TestMethod. V tomto testu jsme napsali pouze kód k definování kritérií testu. Vytvořili jsme novou instanci třídy Product a použili jsme metodu Asser.IsFalse() ke zjištění, že tvrzení vlastnost IsDirty má hodnotu nepravda (false). Samozřejmě, pokud se pokusíte zkompilovat tento kód, tak spadne kvůli tomu, že ještě nemáme nadefinovanou třídu Product. V této fázi jsme Červení - máme selhávající (nepropustný) test (jak vidíte, selhání při kompilaci je také selhání).

Zelená

Dalším krokem je napsaní kódu, který potřebujeme ke splnění požadavků (aby test prošel). Stačí tedy vytvořit nový ClassLibrary projekt, kde umístíme třídu Product. Vytvoření třídy Product:


using System;
using System.Collections.Generic;
using System.Text;

namespace MyLibrary { 
  public class Product {}
} 

Po vytvoření třídy Product (a přidáním reference do projektu ClassLibrary v našem projektu Test), Test projekt stále nepůjde zkompilovat, jelikož test ještě neprojde. Potřebujeme tedy splnit požadavek na vlastnost IsDirty, aby vracela nepravdu (false). To uděláme takto:


public class Product { 
  public bool IsDirty = false;
}

Předchozí kód splňuje požadavky, které byly definovány. Je velmi jednoduché, přidat nějaký další kód (například možnost vrácení hodnoty pravda (true) v této vlastnosti), ale ještě jsme neobdrželi požadavek pro tuto funkčnost. Jeden z klíčových principů TDD je malý přírůstkový proces pro vytváření software. Můžete zdokumentovat požadavky v testu. Poté napsat pouze kód, který tímto testem projde. A nakonec vyčistit kód, pokud je to nezbytné, a pokračovat dalším požadavkem. Je nutné však psát POUZE kód, který je potřebný ke splnění požadavků (například, aby prošel testem).

Teď my máme kód a oba projekty bychom měli zkompilovat. Jakmile jsou projekty zkompilovány, můžete spustit programátorův test, abyste viděli, zda projde (uvidíte, jestli jste splnili požadavky). Klikněte na zelenou šipku na VSTS toolbaru, jak je ukázáno zde:

Když test běží, okno Test Result (výsledek testu) se otevře a test má ikonu „!&ldquo, která indikuje, že test je připraven ke spuštění. Jakmile test proběhne, uvidíte, že se ikona změnila na zelený kruh se zaškrtnutím nebo na červený kruh s X. Zelená barva indikuje, že test prošel, zatímco červená indikuje, že neprošel (už vidíte odkud Červený, Zelený, Refaktor pochází :). Protože náš kód je přesně kód dostačující k projití testu, dostaneme zelenou ikonu a můžeme pokračovat.

Refaktor

Další krok je refaktorování (pokud neznáte tento termín, tak zde je definice - pozn. překladatele) našeho kódu, je-li je to možné. Vrátíme se zpět k Beckovým pravidlům, zde refaktorování znamená odstranění duplicity. Připomínám, dle definice refaktorace, že refaktorace slouží ke zlepšení kódu beze změny funkčnosti. Pokud se podíváme na kód, který jsme napsali, zjistíme, že zde nepotřebujeme žádné refaktorování.

Opakování a vzestup

V tomto bodě se můžeme vrátit k našemu Seznamu testů a napsat programátorský test, který reprezentuje další požadavek.


/// 
/// Vytvoří Product, změní jméno a zkontroluje, zda je IsDirty pravda.
/// 
[TestMethod]
public void ChangeProductName() {
  Product prod = new Product();
  prod.Name = "New name";
  Assert.IsTrue(prod.IsDirty, "Po změně Product.Name, Product.IsDirty by měla být pravda")}

Předchozí test neprošel ani kompilací, protože nemáme vlastnost Name. Další krok je tedy napsat pouze kód, aby se projekt zkompiloval.


public class Product { 
  public bool IsDirty = false;
  public string Name; 
}

Po napsání tohoto kódu se oba projekty zkompilují. Dále spusťte váš unit test. Kontrola, zda je vlastnost isDirty false (CheckIsDirty), projde, ale test na změnu jména (ChangeProductName) spadne.

I když je kód zkompilován, stále nemáme kompletní implementaci, která naplňuje požadavky (jsme v červeném stavu). Proto přidáme část, která to spraví.


public class Product { 
  public bool IsDirty = false;
  public string Name { 
    set { IsDirty = true; }
  }
}

Po zkompilování obou projektů oba testy projdou. Máme tedy splněny dva požadavky. A teď nastává čas k optimalizaci (refaktorace). Pokud se podíváme na program, kód funkčnosti vypadá čistě tak, jak by měl být. Ale je zde duplicitní kód v projektu Test. Zde můžete vidět, že lze optimalizovat i kód v Testovém projektu.


[TestClass]
public class ProductTest {
  public ProductTest() {
    // TODO: Add constructor logic here
  }

  Product m_prod;

  [TestInitialize]
  public void Init() { 
    m_prod = new Product();
  }

  /// 
  /// Vytvoří Product a zkontroluje, zda je IsDirty nepravda.
  /// 
  [TestMethod]
  public void CheckIsDirty() {
    Assert.IsFalse(m_prod.IsDirty);
  }

  /// 
  /// Vytvoří Product, změní Product Name a zkontroluje, zda IsDirty je pravda.
  /// 
  [TestMethod]
  public void ChangeProductName() {
    m_prod.Name = "New name";
    Assert.IsTrue(m_prod.IsDirty, "Po změně Product.Name, Product.IsDirty by měla být pravda");
  }
} 

Můžeme použít atribut [TestInitialize] ke změnění metody, aby byla vykonáná před každým testem, který spustíme. ([ClassInitialize] atribut způsobí, že metoda bude vykonána pouze jednou, když se spustí první test.) Dokončili jsme tedy kroky Červený/Zelený/Refaktor. Teď můžeme jít dále na další test v našem seznamu testů.


/// 
/// Vytvoří Product, změní Product Name a zkontroluje, zda je ProductName změněn.
/// 
[TestMethod]
public void ChangeProductNameVerify() {
  string prodName = "Seven's Death Ray";
  m_prod.Name = prodName;
  Assert.AreEqual(prodName, m_prod.Name, "Po změně Product.Name, hodnota by se měla rovnat hodnotě, kterou jsme vložili");
} 

Všimněte si, zavedli jsem nové tvrzení, a to tvrzení AreEqual (jsou shodné). Mrkněte do dokumentace, zde se dozvíte o dalších možnostech. Náš kód se nezkompiluje, protože vlastnost Product.Name nemá metodu get, to napravíme tímto kódem:


public class Product {
  public bool IsDirty = false;
  public string Name {
    get { return null; }
    set { IsDirty = true; }
  }
} 

Náš kód je teď zkompilován, ale nový test neprojde. Vlastnost Name vrací null, i když jsme očekávali řetězec „Seven's Death Ray&ldquo. Program upravíme takto:


public class Product {
  public bool IsDirty = false;

  private string m_name;
  public string Name {
    get { return m_name; }
    set { 
      IsDirty = true;
      m_name = value;
    }
  }
} 

Teď všechny naše testy projdou. Podíváme se znovu na možnost optimalizace a poté pokračujeme dalším testem.

Shrnutí

V tomto článku jste se dozvěděli o Test Driven Development a jak psát software použitím TDD s Visual Studio 2005 Team System. Doufám, že jste se dozvědeli, jak s trochou disciplíny a vůlí lze dělat věci trochu jinak, než jak jste byli zvyklý. Teď můžete vyvíjet software s vědomím, že píšete pouze kód, který je potřebný. A dále budete vědět, že nic, co přidáte, změníte nebo odstraníte, nezpůsobí změnu funkčnosti; pokud všechny testy splní podmínky.

Doufám, že budete ochotní vyzkoušet TDD a také si myslím, že shledáte tento způsob psaní kódu velmi návykový. Vypadá to jako nešikovný způsob, ale není tomu tak. Určitě se vám ta trocha práce dostatečně vrátí. V tomto článku to sice vypadá, že k napsání jednoho testu, musíte udělat mnoho úkonů, které zaberou hodně času. Pravda ale je, že napsání jednoho testovacího kódu v tomto článku zabralo pouze několik sekund – nejvíce zabralo vysvětlování každého kroku.

Zdroj: Doug Seven.
Test Driven Development with Visual Studio 2005 Team System
[Internet] 10.3.2006 [12.5.2006]
http://dotnetjunkies.com/Tutorial/9709CE8B-0986-46D2-AE3B-5989F23D3A0F.dcik

×Odeslání článku na tvůj Kindle

Zadej svůj Kindle e-mail a my ti pošleme článek na tvůj Kindle.
Musíš mít povolený příjem obsahu do svého Kindle z naší e-mailové adresy kindle@programujte.com.

E-mailová adresa (např. novak@kindle.com):

TIP: Pokud chceš dostávat naše články každé ráno do svého Kindle, koukni do sekce Články do Kindle.

Hlasování bylo ukončeno    
0 hlasů
Google
Autor pracuje jako programátor na platformě .NET a s databází MSSQL. Baví ho četba(sci-fi, fantasy), jazyky a metafyzika.

Nové články

Obrázek ke článku Stavebnice umělé inteligence 1

Stavebnice umělé inteligence 1

Článek popisuje první část stavebnice umělé inteligence. Obsahuje lineární a plošnou optimalizaci.  Demo verzi je možné použít pro výuku i zájmovou činnost. Profesionální verze je určena pro vývojáře, kteří chtějí integrovat popsané moduly do svých systémů.

Obrázek ke článku Hybridní inteligentní systémy 2

Hybridní inteligentní systémy 2

V technické praxi využíváme často kombinaci různých disciplín umělé inteligence a klasických výpočtů. Takovým systémům říkáme hybridní systémy. V tomto článku se zmíním o určitém typu hybridního systému, který je užitečný ve velmi složitých výrobních procesech.

Obrázek ke článku Jak vést kvalitně tým v IT oboru: Naprogramujte si ty správné manažerské kvality

Jak vést kvalitně tým v IT oboru: Naprogramujte si ty správné manažerské kvality

Vedení týmu v oboru informačních technologií se nijak zvlášť neliší od jiných oborů. Přesto však IT manažeři čelí výzvě v podobě velmi rychlého rozvoje a tím i rostoucími nároky na své lidi. Udržet pozornost, motivaci a efektivitu týmu vyžaduje opravdu pevné manažerské základy a zároveň otevřenost a flexibilitu pro stále nové výzvy.

Obrázek ke článku Síla týmů se na home office může vytrácet. Odborníci radí, jak z pracovních omezení vytěžit maximum

Síla týmů se na home office může vytrácet. Odborníci radí, jak z pracovních omezení vytěžit maximum

Za poslední rok se podoba práce zaměstnanců změnila k nepoznání. Především plošné zavedení home office, které mělo být zpočátku jen dočasným opatřením, je pro mnohé už více než rok každodenní realitou. Co ale dělat, když se při práci z domova ztrácí motivace, zaměstnanci přestávají komunikovat a dříve fungující tým se rozpadá na skupinu solitérů? Odborníci na personalistiku dali dohromady několik rad, jak udržet tým v chodu, i když pracovní podmínky nejsou ideální.

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý