<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>AspectWorks Blog</title>
	<atom:link href="http://www.aspectworks.com/cs/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.aspectworks.com/cs/blog</link>
	<description>Blog o softwarovém vývoji</description>
	<lastBuildDate>Fri, 23 Jul 2010 07:02:06 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>JUnit result interceptor</title>
		<link>http://www.aspectworks.com/cs/blog/2010/07/junit-result-interceptor/</link>
		<comments>http://www.aspectworks.com/cs/blog/2010/07/junit-result-interceptor/#comments</comments>
		<pubDate>Tue, 20 Jul 2010 09:18:40 +0000</pubDate>
		<dc:creator>Luboš Račanský</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Testování]]></category>

		<guid isPermaLink="false">http://www.aspectworks.com/cs/blog/?p=648</guid>
		<description><![CDATA[Před nějakou dobou jsme psali o vlastní anotaci @AfterFailure v JUnit testech. Naší motivací byly screenshoty neúspěšných selenium testů. JUnit od verze 4.7 má svoje řešení jménem TestWatchman.
TestWatchman je v podstatě interceptor, který můžete zavěsit na události failed, finished, starting a succeeded. Ukažme si na následujícím příkladě, jak zareagovat na neúspěšný test a zjistit jméno [...]]]></description>
			<content:encoded><![CDATA[<p>Před nějakou dobou jsme psali o vlastní <a href="http://www.aspectworks.com/cs/blog/2010/04/junit-anotace-afterfailure/">anotaci @AfterFailure v JUnit testech</a>. Naší motivací byly screenshoty neúspěšných selenium testů. JUnit od verze 4.7 má svoje řešení jménem <a href="http://kentbeck.github.com/junit/javadoc/latest/org/junit/rules/TestWatchman.html">TestWatchman</a>.<span id="more-648"></span></p>
<p>TestWatchman je v podstatě interceptor, který můžete zavěsit na události <em>failed, finished, starting a succeeded</em>. Ukažme si na následujícím příkladě, jak zareagovat na neúspěšný test a zjistit jméno třídy a název testu. Tento string používáme jako jméno screenshotu v našich selenium testech. Metoda failed se volá jak při assertationFailed tak při výjimce.</p>
<pre class="brush: java;">
import static junit.framework.Assert.fail;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.MethodRule;
import org.junit.rules.TestWatchman;
import org.junit.runners.model.FrameworkMethod;

public class MyTest {

	@Rule
	public MethodRule watchman = new TestWatchman() {
		@Override
		public void failed(Throwable e, FrameworkMethod method) {
			String methodName = MyTest.this.getClass().getSimpleName() + &quot;.&quot; + method.getName();
			System.out.println(methodName + &quot; has failed!&quot;);
		}
	};

	@Test
	public void testFailed() {
		fail();
	}

}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.aspectworks.com/cs/blog/2010/07/junit-result-interceptor/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Selenium a návrhový vzor Page Objects</title>
		<link>http://www.aspectworks.com/cs/blog/2010/06/selenium-a-navrhovy-vzor-page-objects/</link>
		<comments>http://www.aspectworks.com/cs/blog/2010/06/selenium-a-navrhovy-vzor-page-objects/#comments</comments>
		<pubDate>Tue, 29 Jun 2010 22:08:38 +0000</pubDate>
		<dc:creator>Pavel Müller</dc:creator>
				<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.aspectworks.com/cs/blog/?p=623</guid>
		<description><![CDATA[Selenium používáme úspěšně už několik posledních projektů. Vždycky byly automatizované testy přínosem pro kvalitu aplikace a ušetřily obrovské množství rutinní práce testerům. Představa, že lze vytvořit Selenium test tak, že se &#8220;nakliká&#8221;, a pak ho už budeme jen dokola pouštět, vezme hodně rychle za své. Je jasné, že některé části testů bude potřeba použít několikrát [...]]]></description>
			<content:encoded><![CDATA[<p>Selenium používáme úspěšně už několik posledních projektů. Vždycky byly automatizované testy přínosem pro kvalitu aplikace a ušetřily obrovské množství rutinní práce testerům. Představa, že lze vytvořit Selenium test tak, že se &#8220;nakliká&#8221;, a pak ho už budeme jen dokola pouštět, vezme hodně rychle za své. Je jasné, že některé části testů bude potřeba použít několikrát a že <a href="http://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY princip</a> platí i zde. Nakonec stejně nezbývá nic než použít skriptovací nebo programovací jazyk a Selenium testy udržovat jako každý jiný kód. Jak ale testy navrhovat a strukturovat? S tím jsme se nějakou dobu potýkali. Až jsem objevil návrhový vzor <a href="http://code.google.com/p/selenium/wiki/PageObjects">Page Objects</a>.<br />
<span id="more-623"></span></p>
<p>Pro představu. Máme za úkol pokrýt testy funkčnost založení uživatele. Máme dvě poměrně jednoduché obrazovky:</p>
<p><strong><em>Seznam uživatelů</em></strong>:</p>
<p><a href="http://www.aspectworks.com/cs/blog/wp-content/uploads/2010/06/userList2.png"><img class="alignnone size-medium wp-image-240" title="User List" src="http://www.aspectworks.com/cs/blog/wp-content/uploads/2010/06/userList2.png" alt="" width="600" height="284" /></a></p>
<p><strong><em>Vytvoření nového uživatele</em></strong>:</p>
<p><a href="http://www.aspectworks.com/cs/blog/wp-content/uploads/2010/06/userCreate.png"><img class="size-full wp-image-240 alignleft" title="New User" src="http://www.aspectworks.com/cs/blog/wp-content/uploads/2010/06/userCreate.png" alt="" width="600" height="284" /></a></p>
<p>Jeden test bude na pozitivní scénář založení uživatele. Další test bude na založení uživatele s existujícím uživatelským jménem. Potud je to dobré a vystačili bychom si i s naklikanými testy. Ale jak se začnou množit další scénáře vyžadující založeného uživatele, začínáme se dostávat do problémů. Editovat uživatele, smazat uživatele, zablokovat uživatele, založit požadavek s uživatelem s příslušnou rolí, atd. Původně jsme to řešili privátními metodami v rámci test třídy. To ale nestačí, pokud potřebuji např. založit uživatele v rámci jiného testu. Tak si začnu vytvářet různé helper třídy, ale v tu chvíli v tom začíná být trochu zmatek. Člověk neví, jestli daný kód napsat do helper třídy nebo přímo do testu. Nebyli jsme s tímto stavem spokojeni.</p>
<p>Page Objects návrhový vzor to krásně řeší. Zjednodušeně vytvářím dva druhy tříd. Testy a stránky (Page Object). Page obsahuje metody, které znamenají služby, jaké stránka nabízí z pohledu uživatele. Např. tlačítka, vyplnění formuláře, odkazy, atd. Další metody umožňují zjišťovat stav, v jakém se stránka nachází. Např. počet záznamů v tabulce, přítomnost chybové hlášky, atd. Všechny tyto metody jsou implementovány pomocí Selenium API.</p>
<p>Testy samotné pak naopak nepoužívají Selenium API vůbec. Pouze sestavují testovací scénář voláním sérií služeb na jednotlivých stránkách. A pak také obsahují veškeré asserty. Zjistí stav pomocí metody na stránce a ověří ho. Asserty nepatří do stránky a zase Selenium volání nepatří do testu. S těmito jednoduchými pravidly se dají vytvářet velmi přehledné a čitelné testy.</p>
<p>Tady je příklad na otestování funkce založení uživatele v <a href="http://www.orinoco.cz/">Orinoco</a> platformě.</p>
<p>Stránka odpovídající formuláři na založení uživatele:</p>
<pre class="brush: java;">
@Page
public class CreateUserPage extends AbstractOrinocoPage {

    @Override
    public boolean isValidPage() {
        return selenium.isElementPresent(&quot;page_user__createUser__do&quot;);
    }

    public CreateUserPage fillForm(TestUser user) {
        selenium.type(&quot;username&quot;, user.getUserName());
        selenium.type(&quot;password&quot;, user.getPassword());
        selenium.type(&quot;confirmedPassword&quot;, user.getPassword());
        for (String userType : user.getUserTypes()) {
            selenium.addSelection(&quot;name=roles&quot;, &quot;value=&quot; + userType);
        }
        selenium.type(&quot;firstName&quot;, user.getFirstName());
        selenium.type(&quot;lastName&quot;, user.getSurname());
        selenium.type(&quot;email&quot;, user.getEmail());
        return this;
    }

    public UserListPage create() {
        clickAndWait(&quot;common_action_create_button&quot;);
        return navigateTo(UserListPage.class);
    }

}
</pre>
<p>Jsou tam implementovány dvě &#8220;služby&#8221;. Vyplnění formuláře a stisknutí tlačítka Create. Všimněte si, že zde se přímo používá Selenium API. Dobré bývá také pracovat s daty tak, že jsou zapouzdřené do objektů. Na jednom z projektů jsme dokonce použili přímo DTO objekty, protože už byly hotové a odpovídaly přesně formulářům. Chybí metoda pro Storno tlačítko, ale to nevadí. Doplní se, až bude potřeba pro nějaký scénář. Předek této třídy dává tušit, že bude obsahovat metody odpovídající hlavnímu menu a celému záhlaví.</p>
<p>Takto vypadá Page objekt pro seznam uživatelů:</p>
<pre class="brush: java;">

@Page
public class UserListPage extends AbstractOrinocoPage {

    @Override
    public boolean isValidPage() {
        return selenium.isElementPresent(&quot;page_user__listUsers__do&quot;);
    }

    public CreateUserPage createUser() {
        clickAndWait(&quot;//a[@href='createUser.do']&quot;);
        return navigateTo(CreateUserPage.class);
    }

    public TableControl getUserTable() {
        return getTableControl();
    }

}
</pre>
<p>Je tu implementována jenom jedna metoda na přidání nového uživatele. Za zmínku určitě stojí navigace. Každá metoda, která něco dělá s aplikací, vrací objekt typu Page. Buď vrací novou stránku při přechodu nebo sebe sama, pokud browser zůstává na stejné stránce. Metoda getUserTable() jenom zjišťuje stav na stránce. TableControl je pomocný objekt na práci s tabulkami. Ani na jedné ze stránek není jediný assert. Ten přísluší Test třídě.</p>
<p>Test case pro správu uživatelů:</p>
<pre class="brush: java;">
public class UserManagementTest extends AbstractOrinocoTest {

	private DashboardPage dashboardPage;

	@Before
	public void login() {
		dashboardPage = loginPage.login(&quot;habele&quot;, &quot;a&quot;);
	}

	@Test
	public void createUser() {
		TestUser user = new TestUser(&quot;selAdmin&quot;, &quot;selAdmin&quot;, Arrays.asList(TestUserType.ADMIN),
				&quot;selAdmin&quot;, &quot;selAdmin&quot;, &quot;selAdmin@aspectworks.com&quot;, true);

		UserListPage userListPage = dashboardPage.openSettings().openUserManagement();
		CreateUserPage createUserPage = userListPage.createUser();
		createUserPage.fillForm(user).create();

		TableControl userTable = userListPage.getTableControl();
		TableRow row = userTable.getRow(user);
		assertNotNull(row);
		assertEquals(user.getUserName(), row.getCell(3));
	}

}
</pre>
<p>Test case má standardní průběh. Příprava testovacích dat, provedení testu a kontrola výsledku. Se stránkami se velmi dobře pracuje zřetězeně právě kvůli tomu, že metody zase vrací Page objekty. Test už vůbec nepracuje se Selenium API. Vše nechává uvnitř stránek.</p>
<p>Návrhový vzor Page Objects se velmi osvědčil. Je to přirozený návrh tříd podle uživatelského rozhraní. Testy se velmi snadno tvoří a čtou a znovupoužitelnost je velmi dobrá. Ze stránek se navíc dají tvořit další objekty vyšší úrovně zapouzdřující celé moduly. Lze pak třeba založit uživatele jedním řádkem a pokračovat ve psaní skriptu toho, co zrovna testujeme.</p>
<p>V tomto článku nebylo zmíněno ještě několik součástí, které jsou vidět ze zdrojových kódů. Jak jsou stránky a testy konfigurovány a jak jsou tvořeny instance? Jak probíhá navigace mezi stránkami? Jak ověřit, že se browser nachází na stránce, na které je volána metoda služby? Jak funguje TableControl? O tom zas někdy příště.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.aspectworks.com/cs/blog/2010/06/selenium-a-navrhovy-vzor-page-objects/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Generátor rodných čísel</title>
		<link>http://www.aspectworks.com/cs/blog/2010/05/generator-rodnych-cisel/</link>
		<comments>http://www.aspectworks.com/cs/blog/2010/05/generator-rodnych-cisel/#comments</comments>
		<pubDate>Thu, 13 May 2010 08:51:43 +0000</pubDate>
		<dc:creator>Pavel Müller</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Testování]]></category>

		<guid isPermaLink="false">http://www.aspectworks.com/cs/blog/?p=589</guid>
		<description><![CDATA[V poslední době se věnuji automatizovaným Selenium testům jednoho obchodního systému. Při vkládání osob do systému je nutné zadat rodné číslo a systém provádí jeho validaci a sleduje, jestli je v systému unikátní. Abych mohl automatizovat funkčnost zakládání osob, tak jsem se rozhodl, že vytvořím generátor rodných čísel. Není vše ale tak jednoduché, jak by [...]]]></description>
			<content:encoded><![CDATA[<p>V poslední době se věnuji automatizovaným Selenium testům jednoho obchodního systému. Při vkládání osob do systému je nutné zadat rodné číslo a systém provádí jeho validaci a sleduje, jestli je v systému unikátní. Abych mohl automatizovat funkčnost zakládání osob, tak jsem se rozhodl, že vytvořím generátor rodných čísel. Není vše ale tak jednoduché, jak by se mohlo zdát.</p>
<p><span id="more-589"></span>Obvykle každý ví, že rodná čísla se tvoří od roku 1954 ve tvaru <em>yymmdd/xxxx</em> a ta starší mají tvar <em>yymmdd/xxx</em>. Pokud je to žena, přičte se k měsíci 50. Také si každý myslí, že by mělo být rodné číslo dělitelné jedenáci. Ale zde je právě kámen úrazu. Vše je trochu jinak.</p>
<p>Poslední desátá číslice přidávaná od roku 1954 je kontrolní a tvoří se tak, že se vydělí devitimístné číslo jedenácti a zbytek po dělení se použije jako desátá kontrolní číslice. Tím je výsledné desetimístné číslo dělitelné jedenácti. Tedy v případě, že zbytek po dělení nebyl 10. V takovém případě je kontrolní číslice rovna 0, ale tím pádem není celé rodné číslo dělitelné jedenácti. Do roku 1985 bylo přiděleno cca 1000 rodných čísel, která nejsou 				dělitelná 11. Není vyloučeno, že se v minimálním počtu vyskytly i po 				tomto roce.</p>
<p>Navíc od roku 2004 je zavedena možnost v případě, že jsou v nějaký den vyčerpána všechna  platná čtyřčíslí, použít alternativní rodné číslo, u kterého mají muži k  číslu měsíce přičteno 20 a ženy 70. A i rodná čísla před rokem 1954 mohou mít čtyřčíslí, pokud se jednalo o dodatečně přidělená rodná čísla (např. při získání občanství).</p>
<p>Více informací třeba na <a title="Wikipedii" href="http://cs.wikipedia.org/wiki/Rodn%C3%A9_%C4%8D%C3%ADslo">Wikipedii</a> nebo na <a href="http://latrine.dgx.cz/jak-overit-platne-ic-a-rodne-cislo">tomto blogu</a>.</p>
<p>Většina aplikací se spokojí s ověřením dělitelnosti jedenácti. Ale to je evidentně špatně. Ještěže nemám tu smůlu a nemám nestandardní rodné číslo <img src='http://www.aspectworks.com/cs/blog/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>Napsal jsem pro účely Selenium testů generátor rodných čísel s několika možnostmi, jak číslo generovat:</p>
<ul>
<li>pro konkrétní datum a pohlaví</li>
<li>pro věkové rozpětí &#8211; vhodné třeba pro generování mladistvých</li>
<li>oficiální rodné číslo &#8211; dle výše popsaných pravidel</li>
<li>běžné rodné číslo &#8211; takové, které čeká většina aplikací &#8211; dělitelnost 11, standarní tvary</li>
<li>speciální rodné číslo &#8211; takové, které není běžné &#8211; vhodné pro test validace</li>
</ul>
<p>Ukázka použití generátoru:</p>
<pre class="brush: java;">

// generates random personal number from 1900 till today
String personalNumber = RcGenerator.generateRc();

// men between 18 and 30
personalNumber = RcGenerator.generateRcForAge(18, 30, Gender.MALE);

// common personal number modulo 11 == 0 which passes most validators
personalNumber = RcGenerator.generateRc(RcType.COMMON);
</pre>
<p>Přiložené třídy můžete volně použít. Budu rád, když najdete chyby nebo generátor vylepšíte, rozšíříte funkčnost a s kódem se zase podělíte.</p>
<p><a rel="attachment wp-att-594" href="http://www.aspectworks.com/cs/blog/2010/05/generator-rodnych-cisel/rcgenerator/"></a><a href="http://www.aspectworks.com/cs/blog/wp-content/uploads/2010/05/RcGenerator.zip">RcGenerator.zip</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.aspectworks.com/cs/blog/2010/05/generator-rodnych-cisel/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>JUnit anotace @AfterFailure</title>
		<link>http://www.aspectworks.com/cs/blog/2010/04/junit-anotace-afterfailure/</link>
		<comments>http://www.aspectworks.com/cs/blog/2010/04/junit-anotace-afterfailure/#comments</comments>
		<pubDate>Mon, 26 Apr 2010 11:07:42 +0000</pubDate>
		<dc:creator>Luboš Račanský</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Testování]]></category>

		<guid isPermaLink="false">http://www.aspectworks.com/cs/blog/?p=545</guid>
		<description><![CDATA[Na automatické testování GUI našeho produktu Orinoco používáme framework Selenium. Pro identifikaci a opravu chyby je často klíčové vědět, co uživatel(respektive selenium test) v okamžiku chyby viděl. Selenium umí uložit snímek obrazovky, ale jak definovat okamžik, kdy ho má vytvořit? Nechtěli jsme mít přesně definované, které obrazovky má pokaždé ukládat. Naopak jsme  chtěli snímek [...]]]></description>
			<content:encoded><![CDATA[<p>Na automatické testování GUI našeho produktu <a href="http://www.orinoco.cz">Orinoco</a> používáme framework <strong>Selenium</strong>. Pro identifikaci a opravu chyby je často klíčové vědět, co uživatel(respektive selenium test) v okamžiku chyby viděl. Selenium umí uložit snímek obrazovky, ale jak definovat okamžik, kdy ho má vytvořit? Nechtěli jsme mít přesně definované, které obrazovky má pokaždé ukládat. Naopak jsme  chtěli snímek jen v případě, když Selenium test selže. A k tomu právě lze využít vlastní anotaci <em>@AfterFailure</em>.<br />
<span id="more-545"></span><br />
Na začátku byla jasná představa: ukládat snímky obrazovky, pokud Selenium test selže. Zbývalo jen   doplnit metodu <i>Selenium#captureScreenshot(String)</i> na správné místo. Narazil jsem na zajímavý článek <a href="https://dev.youdevise.com/YDBlog/index.php?title=capture_screenshots_of_selenium_browser_&amp;more=1&amp;c=1&amp;tb=1&amp;pb=1">Capture Screenshots of Selenium Failures</a>, který popisuje, jak anotaci @AfterFailure a vlastní Runner naprogramovat.</p>
<p>Pozor na pořadí anotací! Řešení popsané ve zmiňovaném článku volá nejprve metodu anotovanou @After a poté teprve @AfterFailure. To samo o sobě není problém, pokud stejně jako my v metodě anotované @After nevoláte metodu <i>Selenium#stop()</i>, která zavírá prohlížeč. To pak vám je získaný snímek obrazovky k ničemu. Rešení je jednoduché, stačí v runneru jen prohodit volání metod v metodě <i>#withAfters(FrameworkMethod, Object, Statement)</i>.
<pre class="brush: java;">
@Override
protected Statement withAfters(FrameworkMethod method, Object target, Statement statement) {
      statement = withAfterFailures(method, target, statement);
      return super.withAfters(method, target, statement);
}
</pre>
<p>Věřím, že vám snímky v případě selhání Selenium testů ušetří čas při opravování bugů.</p>
<p><em>Edit</em><br />
JUnit od verze 4.7 má svoje <a href="http://www.aspectworks.com/cs/blog/2010/07/junit-result-interceptor/">řešení jménem TestWatchman</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.aspectworks.com/cs/blog/2010/04/junit-anotace-afterfailure/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Unit testy nad in-memory databází</title>
		<link>http://www.aspectworks.com/cs/blog/2010/03/unit-testy-nad-in-memory-databazi/</link>
		<comments>http://www.aspectworks.com/cs/blog/2010/03/unit-testy-nad-in-memory-databazi/#comments</comments>
		<pubDate>Sun, 21 Mar 2010 13:02:31 +0000</pubDate>
		<dc:creator>Richard Šerý</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Testování]]></category>

		<guid isPermaLink="false">http://www.aspectworks.com/cs/blog/?p=496</guid>
		<description><![CDATA[Použití in-memory databází pro testování je poněkud kontroverzní téma, ale nedělejte rychlé soudy &#8211; Tomáš Piňos na svém blogu naznačuje, za jakých okolností má testování za pomoci in-memory databáze svoje opodstatnění. Nenechte si ujít zajímavý článek &#8220;Unit testy nad in-memory databází&#8220;.
]]></description>
			<content:encoded><![CDATA[<p>Použití in-memory databází pro testování je poněkud kontroverzní téma, ale nedělejte rychlé soudy &#8211; Tomáš Piňos na svém blogu naznačuje, za jakých okolností má testování za pomoci in-memory databáze svoje opodstatnění. Nenechte si ujít zajímavý článek &#8220;<a href="http://tom2ee-cs.blogspot.com/2010/02/unit-testy-nad-in-memory-databazi.html">Unit testy nad in-memory databází</a>&#8220;.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.aspectworks.com/cs/blog/2010/03/unit-testy-nad-in-memory-databazi/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rozbiješ build, seřve tě Tux!</title>
		<link>http://www.aspectworks.com/cs/blog/2010/03/rozbijes-build-serve-te-tux/</link>
		<comments>http://www.aspectworks.com/cs/blog/2010/03/rozbijes-build-serve-te-tux/#comments</comments>
		<pubDate>Tue, 02 Mar 2010 13:14:38 +0000</pubDate>
		<dc:creator>Pavel Müller</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Jen tak]]></category>

		<guid isPermaLink="false">http://www.aspectworks.com/cs/blog/?p=467</guid>
		<description><![CDATA[
V AspectWorks jsme fanoušky kontinuální integrace. Píšeme unit testy, snažíme se o dobré pokrytí kódu a s každým commitem do SVN spouštíme integrační build. Aktuálně používáme TeamCity jako server na kontinuální integraci. O selhaných buildech nás doteď informovaly emaily,  Jabber, vyskakovací okýnka v Eclipse, atd. Nuda!
Teď jsme si ale pořídili tu správnou vychytávku na [...]]]></description>
			<content:encoded><![CDATA[<p><img  class="imageRight" src="http://www.aspectworks.com/cs/blog/wp-content/uploads/2010/03/tux21.png" alt="Tux Droid" title="Tux Droid" width="150" height="150" class="alignright size-full wp-image-491" /></p>
<p>V AspectWorks jsme fanoušky kontinuální integrace. Píšeme unit testy, snažíme se o dobré pokrytí kódu a s každým commitem do SVN spouštíme integrační build. Aktuálně používáme TeamCity jako server na kontinuální integraci. O selhaných buildech nás doteď informovaly emaily,  Jabber, vyskakovací okýnka v Eclipse, atd. Nuda!</p>
<p>Teď jsme si ale pořídili tu správnou <a href="http://www.kysoh.com/tux-droid">vychytávku</a> na notifikaci o buildech: <a href="http://wiki.waltercedric.com/index.php?title=Tux_Droid_Plugin_For_TeamCity_Continuous_BuildServer">Tux plugin do TeamCity</a>.</p>
<p><span id="more-467"></span></p>
<p>Jak to funguje? Jednoduše &#8211; když někdo rozbije build, tučňák Tux začne křičet, který build selhal. </p>
<p>Pokud nemáte zrovna TeamCity, nevadí &#8211; Tux API je docela jednoduché, takže si můžete celkem rychle udělat plugin pro vlastní build server.</p>
<pre class="brush: java;">
TuxAPI tux = new TuxAPI(ipAdress, port);
tux.server.autoConnect(TuxAPIConst.CLIENT_LEVEL_RESTRICTED, &quot;login&quot;, &quot;password&quot;);
tux.tts.speak(&quot;Text to speach&quot;);
</pre>
<p>Vřele doporučuju nějakou takovou blbinu zavést.</p>
<p><img src="http://www.aspectworks.com/cs/blog/wp-content/uploads/2010/03/tux.png" alt="Tux" title="Tux" width="648" height="418" class="alignright size-full wp-image-482" /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.aspectworks.com/cs/blog/2010/03/rozbijes-build-serve-te-tux/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Spring: podmíněná konfigurace</title>
		<link>http://www.aspectworks.com/cs/blog/2010/02/spring-podminena-konfigurace/</link>
		<comments>http://www.aspectworks.com/cs/blog/2010/02/spring-podminena-konfigurace/#comments</comments>
		<pubDate>Tue, 09 Feb 2010 13:26:47 +0000</pubDate>
		<dc:creator>Luboš Račanský</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[konfigurace]]></category>

		<guid isPermaLink="false">http://www.aspectworks.com/cs/blog/?p=435</guid>
		<description><![CDATA[Při vývoji aplikací ve Springu jste jistě narazili na problém nasazení do různých prostředí. Pravděpodobně jste to řešili vytvořením samostatných buildů. Ovšem ne vždy je to potřeba. Proč nenechat konfiguraci na adminovi? Existuje jednoduché a elegantní řešení jménem BeanReferenceFactoryBean.

BeanReferenceFactoryBean využijete zejména, nastavujete-li specifická prostředí, jako je TaskExecutor pro Scheduling, transakční manažer, autentizaci atd.
Představte si například [...]]]></description>
			<content:encoded><![CDATA[<p>Při vývoji aplikací ve Springu jste jistě narazili na problém nasazení do různých prostředí. Pravděpodobně jste to řešili vytvořením samostatných buildů. Ovšem ne vždy je to potřeba. Proč nenechat konfiguraci na adminovi? Existuje jednoduché a elegantní řešení jménem <strong>BeanReferenceFactoryBean</strong>.<br />
<span id="more-435"></span><br />
BeanReferenceFactoryBean využijete zejména, nastavujete-li specifická prostředí, jako je TaskExecutor pro Scheduling, transakční manažer, autentizaci atd.</p>
<p>Představte si například situaci, kdy v properties vaší aplikace potřebujete nastavit, zda se <strong>Spring Security</strong> bude autentizovat vůči databázi nebo vůči LDAPu. </p>
<h3 class="block">Jak na to?</h3>
<p>Nejdříve nastavte v properties takovýto klíč:<br />
<code>myApplication.authentication.provider=ldap</code></p>
<p>Target beana libovolného jména definovaného v properties bude díky <strong>BeanReferenceFactoryBean</strong> dostupná vždy pod jediným a předem známým id.</p>
<pre class="brush: xml;">
&lt;bean id=&quot;authenticationProvider&quot; class=&quot;org.springframework.beans.factory.config.BeanReferenceFactoryBean&quot;&gt;
	&lt;property name=&quot;targetBeanName&quot;&gt;
		&lt;value&gt;${myApplication.authentication.provider}AuthenticationProvider&lt;/value&gt;
      &lt;/property&gt;
&lt;/bean&gt;
</pre>
<p>Do <em>authentication-manageru</em> nainjektujeme beanu <em>authenticationProvider</em>, jejíž target beana je zvolena právě na základě konfigurace v properties.</p>
<pre class="brush: xml;">
&lt;sec:authentication-manager&gt;
	&lt;sec:authentication-provider ref=&quot;authenticationProvider&quot;/&gt;
&lt;/sec:authentication-manager&gt;
</pre>
<p>Pro úplnost ještě uvádím nástin konfigurace Spring Security vůči databázi a LDAP.</p>
<pre class="brush: xml;">
&lt;bean id=&quot;dbAuthenticationProvider&quot; class=&quot;org.springframework.security.authentication.dao.DaoAuthenticationProvider&quot; lazy-init=&quot;true&quot;&gt;
	&lt;property name=&quot;userDetailsService&quot; ref=&quot;userDetailsService&quot; /&gt;
&lt;/bean&gt;
</pre>
<p>Lazy-init je nastaveno na <em>true</em>, protože pokud si vyberete autentizaci vůči databázi, tak nebudete konfigurovat LDAP a naopak. S nevalidním nastavením by vám pak vůbec nenaběhl aplikační kontext.</p>
<pre class="brush: xml;">
&lt;bean id=&quot;ldapAuthenticationProvider&quot; class=&quot;org.springframework.security.ldap.authentication.LdapAuthenticationProvider&quot; lazy-init=&quot;true&quot;&gt;
	&lt;!-- configuration of LDAP --&gt;
&lt;/bean&gt;
</pre>
<p>Místo nového buildu teď stačí pro změnu konfigurace jen upravit nastavení v properties a restartovat aplikační server.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.aspectworks.com/cs/blog/2010/02/spring-podminena-konfigurace/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Verzování datového modelu a LiquiBase</title>
		<link>http://www.aspectworks.com/cs/blog/2010/02/verzovani-datoveho-modelu-a-liquibase/</link>
		<comments>http://www.aspectworks.com/cs/blog/2010/02/verzovani-datoveho-modelu-a-liquibase/#comments</comments>
		<pubDate>Tue, 02 Feb 2010 15:54:58 +0000</pubDate>
		<dc:creator>Richard Šerý</dc:creator>
				<category><![CDATA[Jen tak]]></category>

		<guid isPermaLink="false">http://www.aspectworks.com/cs/blog/?p=420</guid>
		<description><![CDATA[Liquibase je populární nástroj pro správu datového modelu. O jeho použití, i o různých činnostech, týkajících se správy datového modelu, sepsal náš kolega Tomáš Piňos pěkný článek &#8211; přečtěte si ho!
]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.aspectworks.com/cs/blog/wp-content/uploads/2010/02/liquibase_logo.gif" alt="LiquiBase" title="liquibase_logo" width="200" height="37" class="imageRight" />Liquibase je populární nástroj pro správu datového modelu. O jeho použití, i o různých činnostech, týkajících se správy datového modelu, sepsal náš kolega Tomáš Piňos <a href="http://tom2ee-cs.blogspot.com/2010/01/verzovani-datoveho-modelu-liquibase.html">pěkný článek &#8211; přečtěte si ho!</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.aspectworks.com/cs/blog/2010/02/verzovani-datoveho-modelu-a-liquibase/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JBoss versus Spring</title>
		<link>http://www.aspectworks.com/cs/blog/2009/11/jboss-versus-spring/</link>
		<comments>http://www.aspectworks.com/cs/blog/2009/11/jboss-versus-spring/#comments</comments>
		<pubDate>Tue, 24 Nov 2009 10:40:36 +0000</pubDate>
		<dc:creator>Pavel Müller</dc:creator>
				<category><![CDATA[Jen tak]]></category>

		<guid isPermaLink="false">http://www.aspectworks.com/cs/blog/?p=388</guid>
		<description><![CDATA[Ještě zhruba před rokem jsem si myslel, že JBoss a Spring nejdou v ničem proti sobě. JBoss je převážně aplikační server a Spring je framework na snadný vývoj lehčích JEE aplikací. Není přeci problém postavit webovou aplikaci na Spring frameworku a nasadit ji na JBoss server. Dokonce jsme to se svými projekty dělali a děláme [...]]]></description>
			<content:encoded><![CDATA[<p>Ještě zhruba před rokem jsem si myslel, že JBoss a Spring nejdou v ničem proti sobě. JBoss je převážně aplikační server a Spring je framework na snadný vývoj lehčích JEE aplikací. Není přeci problém postavit webovou aplikaci na Spring frameworku a nasadit ji na JBoss server. Dokonce jsme to se svými projekty dělali a děláme i nadále. K hlubšímu zamyšlení na toto téma mě přivedla až jedna ostřejší diskuze během JBoss školení. O co jde?</p>
<p><span id="more-388"></span></p>
<p><img src="http://www.aspectworks.com/cs/blog/wp-content/uploads/2009/11/jboss-vs-spring.png" alt="JBoss versus Spring" title="JBoss versus Spring" class="imageRight size-full wp-image-403" /></p>
<p>Pochopitelně jedním základním sporem je volba architektury. Zda jít cestou tzv. standardů a zvolit tak architekturu např. JSF, EJB3, JPA a nasadit aplikaci na plnohodnotný JEE aplikační server a nebo jít cestou POJO objektů, Spring kontejneru, Hibernate, AOP zajištujícího middleware služby a celé to nasadit třeba na Tomcat. Až mě překvapuje, kolik Java vývojářů vnímá tuto volbu architektury jako otázku &#8220;buď a nebo&#8221;. Je skutečně nutné se rozhodnout pro jedno, nebo je Spring skutečně jen framework pro zjednodušení práce s JEE aplikacemi?</p>
<p>Dalším a neméně významným třecím místem mezi Springem a JBossem je podle mě konkurence obou komunit. Spring už přece dávno není jen Spring Framework. Je to rychle rostoucí firma, nabízející celou řadu produktů, podobných těm od JBossu. Dokonce takový Spring dm Server je dnes vážný konkurent na poli aplikačních serverů. SpringSource nabízí komerční podporu, nástroje, školení, atd. Na druhé straně JBoss již také není jen server. JBoss Seam je plnohodnotný aplikační framework. Zde už by mohlo být podstatné architektonické rozhodnutí: JBoss Seam nebo Spring Framework?</p>
<p><del>Tímto krátkým úvodem vás zvu na <em>druhé setkání skupiny <a href="http://www.jboss.cz/jbug/">JBoss User Group</a></em>, které se bude konat <em>26.11.2009 od 9 hodin</em>. Na začátku rozvedu výše nastíněná témata JBoss versus Spring a následně bude probíhat diskuze, behěm níž si vyměníme názory a zkušenosti z projektů. <a href="http://www.jboss.cz/jbug/">Těším se na vaší účast</a>.</del></p>
<p><em>Update:</em> Ve čtvrtek 26.11.2009 proběhlo setkání skupiny <a href="http://www.jboss.cz/jbug/">JBoss User Group</a> na téma JBoss versus Spring. Informace o průběhu akce najdete ve zprávě <a href="http://www.aspectworks.com/cs/press/articles2009/jbug-setkani-2.html">Druhé setkání JBug ČR</a>. Můžete si také <a href="http://www.aspectworks.com/download/jbug-2.mp3">stáhnout  hlasový záznam [mp3, 13 MB]</a>  &#8211; omluvte prosím sníženou kvalitu záznamu.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.aspectworks.com/cs/blog/2009/11/jboss-versus-spring/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Testujeme s rozumem (2.) &#8211; Jak z UC získat TC</title>
		<link>http://www.aspectworks.com/cs/blog/2009/11/testujeme-s-rozumem-2-jak-z-uc-ziskat-tc/</link>
		<comments>http://www.aspectworks.com/cs/blog/2009/11/testujeme-s-rozumem-2-jak-z-uc-ziskat-tc/#comments</comments>
		<pubDate>Mon, 02 Nov 2009 10:29:42 +0000</pubDate>
		<dc:creator>Zdeněk Jonáš</dc:creator>
				<category><![CDATA[Testování]]></category>

		<guid isPermaLink="false">http://www.aspectworks.com/cs/blog/?p=362</guid>
		<description><![CDATA[Při přípravě na testování projektu je zapotřebí vytvořit scénáře (postupy), které budou testeři procházet při testování. Scénáře by v optimálním případě měly pokrývat případy užití, pro které je aplikace vyvíjena. Máme-li rozumně zpracovanou analýzu, může být získání těchto scénářů relativně snadné.

Tyto scénáře testů nazýváme „testovanými scénáři“, anglicky test case, zkratkou TC. Co je to TC? [...]]]></description>
			<content:encoded><![CDATA[<p>Při přípravě na testování projektu je zapotřebí vytvořit scénáře (postupy), které budou testeři procházet při testování. Scénáře by v optimálním případě měly pokrývat případy užití, pro které je aplikace vyvíjena. Máme-li rozumně zpracovanou analýzu, může být získání těchto scénářů relativně snadné.<br />
<span id="more-362"></span></p>
<p>Tyto scénáře testů nazýváme „testovanými scénáři“, anglicky test case, zkratkou TC. Co je to TC? Co by měl obsahovat? TC je soubor vstupů, kroků i podmínek a očekávaných výstupů. Ale kde ho vezmeme?</p>
<p>Každá analýza vyvíjeného systému by měla obsahovat případy užití (use cases), dále UC. Tyto scénáře užití lze s výhodou použít pro vytvoření seznamu TC. Jak na to? Ukážeme si na následujícím příkladu.</p>
<div class="example">
<p>Představte si jednoduchý systémový UC na evidenci vydané faktury v nějakém systému. Daný uživatel má právo zadávat faktury pouze do 100 tisíc.</p>
<h4>Basic Flow</h4>
<ul>
<li>1. Uživatel zadá číslo faktury.</li>
<li>2. Systém provede kontrolu čísla faktury.</li>
<li>3. Uživatel vyplní fakturovanou částku.</li>
<li>4. Systém provede kontrolu výše částky.</li>
<li>5. Uživatel vyplní datum splatnosti.</li>
<li>6. Systém provede kontrolu data splatnosti.</li>
<li>7. Systém vytvoří fakturu a podá uživateli zprávu o jejím úspěšném zaevidování.</li>
</ul>
</div>
<p>Nyní máme zpracovaný zcela jednoduchý UC, kde máme základní průchod aplikací. Bohužel svět není jednoduchý a ani náš příklad nemůže být takto jednoduchý. Je zapotřebí se zamyslet a definovat další toky, kterými může tento scénář být přerušen, či pokračovat zcela jinou cestu. Jedná se o tzv. Alternate flows.</p>
<div class="example">
<h4>Alternate flow 1</h4>
<p class="noBottom">Faktura v systému již existuje, nelze přidat.</p>
<ul>
<li>Basic Flow v bodě 2. Systém podá uživateli zprávu o existenci faktury tohoto čísla a UC se tímto ukončí (faktura se nevytvoří).</li>
</ul>
<h4>Alternate flow 2</h4>
<p class="noBottom">Co když částka na faktuře přesáhne hodnotu 100 tis Kč?</p>
<ul>
<li>Basic Flow v bodě 4. Systém podá uživateli zprávu o převýšení maximální hodnoty faktury a UC se tímto ukončí (faktura se nevytvoří).</li>
</ul>
<h4>Alternate flow 3</h4>
<p class="noBottom">Co když zadáme datum splatnosti v minulosti?</p>
<ul>
<li>Basic Flow v bodě 6. Systém podá uživateli zprávu o špatné hodnotě data splatnosti a UC se tímto ukončí (faktura se nevytvoří).</li>
</ul>
</div>
<p>Nyní si sepíšeme do tabulky pod sebe všechny možné scénáře, a pojmenujeme si je. Pojmenování volte rozumně, neboť by se mělo používat skrze celé testování.</p>
<div class="example">
<h3>Sestavení a pojmenování scénářů</h3>
<table border="0">
<tbody>
<tr>
<th>Scénář 1 – založení faktury</th>
<td>Basic Flow</td>
<td></td>
</tr>
<tr>
<th>Scénář 2 – faktura tohoto čísla již v systému existuje</th>
<td>Basic Flow</td>
<td>Alternate flow 1</td>
</tr>
<tr>
<th>Scénář 3 – částka vyšší než 100 tisíc</th>
<td>Basic Flow</td>
<td>Alternate flow 2</td>
</tr>
<tr>
<th>Scénář 4 – datum splatnosti v minulosti</th>
<td>Basic Flow</td>
<td>Alternate flow 3</td>
</tr>
</tbody>
</table>
</div>
<p>Teď již máme identifikovány hlavní scénáře, které budeme potřebovat otestovat. Pro vlastní testování však toto ještě nestačí. Musíme definovat vstupy a očekávané výstupy jednotlivých TC. Vstupy lze identifikovat dle rozhodovacích bloků v UC. Každé alternative flow by mělo být způsobeno nějakou příčinou, vstupem. V našem případě máme situaci poněkud zjednodušenou. V reálných systémech jsou i desítky vstupů. Zde lze s výhodou použít excel, či vhodný TC management nástroj.</p>
<p>V našem případě dochází k startu alternate flow 3 v scénáři č.4: Datum splatnosti v minulosti.<br />
Je tedy evidentní, že v tomto scénáři se rozhodne o provedení alternativního scénáře v bodě 6. Tudíž je zapotřebí zadat číslo faktury, částku a datum splatnosti. Číslo faktury a částka je validní a datum splatnosti je neplatné (Invalid). Další vstupy jsou již pro tento scénář irelevantní a v tabulce se neobjeví.</p>
<p>Nyní vyplňme tabulku. „V“ představuje potřebný validní vstup a „I“ invalidní vstup. Pokud na vstupech nezáleží nebo jsou irelevantní, zanechte příslušné buňku tabulky prázdnou. Názvy jednotlivých TC volíme ve sloupci TC ID# tak, aby odpovídaly testovanému scénáři. V našem případě jde o evidenci faktury, zvolil jsem tedy zkratku IE (Invoice Evidence). V případě velkých systémů nám toto pojmenování pomůže v orientaci.</p>
<div class="example">
<table border="0">
<tbody>
<tr>
<th>TC ID#</th>
<th>Scénář</th>
<th>číslo faktury</th>
<th>částka</th>
<th>datum splatnosti</th>
<th>Očekávaný výsledek</th>
</tr>
<tr>
<td>IE 1</td>
<td>Scénář 1 – založení faktury</td>
<td>V</td>
<td>V</td>
<td>V</td>
<td>Faktura úspěšně založena</td>
</tr>
<tr>
<td>IE 2</td>
<td>Scénář 2 – faktura tohoto čísla již v systému existuje</td>
<td>I</td>
<td></td>
<td></td>
<td>Faktura nezaložena, uživatel informován.</td>
</tr>
<tr>
<td>IE 3</td>
<td>Scénář 3 – částka vyšší než 100 tisíc</td>
<td>V</td>
<td>I</td>
<td></td>
<td>Faktura nezaložena, uživatel informován.</td>
</tr>
<tr>
<td>IE 4</td>
<td>Scénář 4 – datum splatnosti v minulosti</td>
<td>V</td>
<td>V</td>
<td>I</td>
<td>Faktura nezaložena, uživatel informován.</td>
</tr>
</tbody>
</table>
</div>
<p>Nyní máme tabulku validních a nevalidních vstupů. Víme, na kterých vstupech záleží úspěšnost dané operace. Připravíme si testovací prostředí tak, abychom mohli splnit tyto scénáře. Dost často mají UC tzv. preconditions. Tyto precondititons například říkají, že uživatel, který chce založit jiného uživatele, musí mít administrátorská práva. Musíte tedy do systému před začátkem testovaní založit uživatele s administrátorskými právy.<br />
Na základě takto připraveného testovacího prostředí jste již schopni definovat konkrétní tabulku s konkrétními vstupy.<br />
V našem případě vypadá například takto. Pokud používáte excel, doplňte si tabulku o sloupce precondition a postconditions. Tam definujte, co je zapotřebí udělat před spuštěním testu a zároveň co má tester udělat po ukončení testu. (například po sobě v aplikaci uklidit).</p>
<div class="example">
<table border="0">
<tbody>
<tr>
<th>TC ID#</th>
<th>Scénář</th>
<th>číslo faktury</th>
<th>částka</th>
<th>datum splatnosti</th>
<th>Očekávaný výsledek</th>
</tr>
<tr>
<td>IE 1</td>
<td>Scénář 1 – založení faktury</td>
<td>20</td>
<td>45 000</td>
<td>15.1.2010</td>
<td>Faktura úspěšně založena</td>
</tr>
<tr>
<td>IE 2</td>
<td>Scénář 2 – faktura tohoto čísla již v systému existuje</td>
<td>20</td>
<td></td>
<td></td>
<td>Faktura nezaložena, uživatel informován.</td>
</tr>
<tr>
<td>IE 3</td>
<td>Scénář 3 – částka vyšší než 100 tisíc</td>
<td>21</td>
<td>150 000</td>
<td></td>
<td>Faktura nezaložena, uživatel informován.</td>
</tr>
<tr>
<td>IE 4</td>
<td>Scénář 4 – datum splatnosti v minulosti</td>
<td>22</td>
<td>23 000</td>
<td>11.9.2001</td>
<td>Faktura nezaložena, uživatel informován.</td>
</tr>
</tbody>
</table>
</div>
<p>Dost často na svých školeních se setkávám s názorem, že tento postup je příliš přebyrokratizovaný a prý zdržuje. Praxe ovšem ukazuje, že problémem není vyplnění tabulky, ale neochota některých (test) analytiků se dopředu zamyslet a definovat tyto scénáře a vstupy. Pokud se ovšem nechcete smířit s intuitivním testováním a postoupit například až k objektivnímu měření kvality, zavedení podobných pravidel vás nejspíše nemine.</p>
<p>Pozorný čtenář teď zareaguje: Vždyť v těch TC nemám přeci kroky, jak mám postupovat? Tehdy ale nehledáme artefakt TC ale Test Script. Čili postup, kterým bude tester postupovat při ověřování konkrétního testovaného případu. Test Scripty psát je časově náročné a mnohdy se musí s měnící aplikací znovu přepisovat. Proč je tedy píšeme?</p>
<p>Rozdíl mezi TC a Test Script je v době jejich vzniku a v tom, kdo tyto artefakty vytváří. Zatímco k definici TC dochází na začátku projektu a provádí je test analytik (dosti často i analytik projektu), tak Test Scripty si píší sami testeři.</p>
<p>Oblast okolo názvů, tvorby TC a organizace práce je natolik rozsáhlá, že by vydala na několik článků. Pokud máme menší projekty a sdílené role, potřebujeme relativně malý aparát. Pokud ovšem projekt přerůstá určitou hranici, je zapotřebí zvolit adekvátní metody přístupu k testování.</p>
<p><a href="http://www.aspectworks.com/cs/blog/2009/08/testujme-s-rozumem-serial/">Předchozí díl: Úvod seriálu</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.aspectworks.com/cs/blog/2009/11/testujeme-s-rozumem-2-jak-z-uc-ziskat-tc/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
	</channel>
</rss>
