<?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>Splatch's devblog &#187; Testy jednostkowe</title>
	<atom:link href="http://blog.dywicki.pl/category/testy-jednostkowe/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.dywicki.pl</link>
	<description>Pragmatyzm kontrolowany</description>
	<lastBuildDate>Thu, 01 Dec 2011 15:47:57 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=abc</generator>
		<item>
		<title>EasyMock i IAnswer, recepta na zachowanie metod</title>
		<link>http://blog.dywicki.pl/2008/12/03/easymock-inaswer-as-method-behaviour-recipe/</link>
		<comments>http://blog.dywicki.pl/2008/12/03/easymock-inaswer-as-method-behaviour-recipe/#comments</comments>
		<pubDate>Wed, 03 Dec 2008 16:06:42 +0000</pubDate>
		<dc:creator>Łukasz Dywicki</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Porady]]></category>
		<category><![CDATA[Testy jednostkowe]]></category>

		<guid isPermaLink="false">http://blog.dywicki.pl/?p=240</guid>
		<description><![CDATA[Złym zwyczajem jest modyfikowanie argumentów zamiast zwracania nowej wartości, jakkolwiek trafiają się sytuacje gdy testowany kod powinien weryfikować takie wywołania. W EasyMock mamy do dyspozycji w takim przypadku interfejs IAnswer. Jego użycie jest w miarę proste &#8211; dobieramy się do tablicy argumentów i robimy z nią co potrzeba. Oto przykład &#8211; interfejs Populator dodaje do [...]]]></description>
			<content:encoded><![CDATA[<p>Złym zwyczajem jest modyfikowanie argumentów zamiast zwracania nowej wartości, jakkolwiek trafiają się sytuacje gdy testowany kod powinien weryfikować takie wywołania. W EasyMock mamy do dyspozycji w takim przypadku interfejs IAnswer. Jego użycie jest w miarę proste &#8211; dobieramy się do tablicy argumentów i robimy z nią co potrzeba.<br />
<span id="more-240"></span><br />
Oto przykład &#8211; interfejs Populator dodaje do przekazanej tablicy określoną wartość w puste miejsca. Zwraca też ilość zmian, które zaprowadził. Całość jest oparta na bardzo prostym kodzie, zaledwie jedna pętla, jakkolwiek na potrzeby przykładu jest to wystarczające. Pragnę jednak nadmienić, że w podobny sposób można testować bardziej złożony kod, gdzie kolaborują ze sobą dwa obiekty &#8211; tj. Observator i Observable czy też Visitor i Visitable.</p>
<pre class="brush: java;">package org.code_house.test.mock;

interface Populator {
    int fill(String value, String[] arguments);
}
</pre>
<p>Implementacja interfejsu jest bardzo prosta:</p>
<pre class="brush: java;">package org.code_house.test.mock;

class FillAnswer implements IAnswer&lt;Integer&gt; {
    public Integer answer() throws Throwable {
        // pobranie argumentow
        Object[] arguments = EasyMock.getCurrentArguments();
        String name = (String) arguments[0];
        Object[] values = (Object[]) arguments[1];

        // logika potrzebna do testu
        int populated = 0;
        for (int i = 0; i &lt; values.length; i++) {
            if (values[i] == null) {
                populated++;
                values[i] = name;
            }
        }
        return populated;
    }
}
</pre>
<p>Test jest również niezbyt skomplikowany &#8211; bazuje on na poprzedniej nocie &#8211; &#8220;Testowanie tablic argumentów z EasyMock&#8221;:</p>
<pre class="brush: java;">package org.code_house.test.mock;

import static org.easymock.EasyMock.*;
import org.easymock.IAnswer;

import java.util.Arrays;

import junit.framework.TestCase;

public class AnswerTest extends TestCase {

    public void testPopulate() {
        Populator populator = createMock(Populator.class);
        expect(populator.fill(eq(&quot;Code House&quot;), aryEq(new String[3])))
            .andAnswer(new FillAnswer());
        expect(populator.fill(eq(&quot;Code House&quot;), aryEq(new String[] {&quot;1&quot;})))
            .andAnswer(new FillAnswer());
        replay(populator);

        // tablica do wypełnienia
        String[] populated = new String[3];
        int added = populator.fill(&quot;Code House&quot;, populated);
        assertEquals(3, added);
        // w odpowiedzi oczekujemy dodania 3 nowych elementów
        assertTrue(Arrays.equals(
            new String[] {&quot;Code House&quot;, &quot;Code House&quot;, &quot;Code House&quot;},
            populated
        ));

        // w tym przypadku nie oczekujemy nowości
        added = populator.fill(&quot;Code House&quot;, new String[] {&quot;1&quot;});
        assertEquals(0, added);
    }
}
</pre>]]></content:encoded>
			<wfw:commentRss>http://blog.dywicki.pl/2008/12/03/easymock-inaswer-as-method-behaviour-recipe/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Testowanie tablic argumentów z EasyMock</title>
		<link>http://blog.dywicki.pl/2008/11/26/testing-array-parameters-with-easymock/</link>
		<comments>http://blog.dywicki.pl/2008/11/26/testing-array-parameters-with-easymock/#comments</comments>
		<pubDate>Wed, 26 Nov 2008 06:00:02 +0000</pubDate>
		<dc:creator>Łukasz Dywicki</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Porady]]></category>
		<category><![CDATA[Testy jednostkowe]]></category>

		<guid isPermaLink="false">http://blog.dywicki.pl/?p=239</guid>
		<description><![CDATA[Często zdarza się że metody, które piszemy i później testujemy mają argumenty w postaci tablic. EasyMock wówczas potrafi zgłosić wyjątek, że przekazana tablica jest różna od oczekiwanej mimo, że zawartość tablic jest identyczna. java.lang.AssertionError: Unexpected method call find([Ljava.lang.String;@1ad77a7): find([Ljava.lang.String;@b8f82d): expected: 1, actual: 0 package org.code_house.test.mock; import static org.easymock.EasyMock.aryEq; import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.expect; import [...]]]></description>
			<content:encoded><![CDATA[<p>Często zdarza się że metody, które piszemy i później testujemy mają argumenty w postaci tablic. EasyMock wówczas potrafi zgłosić wyjątek, że przekazana tablica jest różna od oczekiwanej mimo, że zawartość tablic jest identyczna.<br />
<span id="more-239"></span></p>
<pre class="brush: java;">java.lang.AssertionError:
  Unexpected method call find([Ljava.lang.String;@1ad77a7):
    find([Ljava.lang.String;@b8f82d): expected: 1, actual: 0
</pre>
<pre class="brush: java;">
package org.code_house.test.mock;

import static org.easymock.EasyMock.aryEq;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;

import java.util.Collections;
import java.util.List;

import junit.framework.TestCase;

interface Finder {
    List&lt;String&gt; find(String[] names);
}

public class FinderTest extends TestCase {

    public void testFind() {
        Finder mock = createMock(Finder.class);
        expect(mock.find(aryEq(new String[] {&quot;Amy&quot;, &quot;Luke&quot;}))).andReturn(
            Collections.EMPTY_LIST);
        replay(mock);

        List&lt;String&gt; list = mock.find(new String[] {&quot;Amy&quot;, &quot;Luke&quot;});
        assertTrue(list.isEmpty());
    }
}
</pre>
<p>Rozwiązaniem tych problemów jest użycie mechanizmu &#8220;matcherów&#8221;, które są wbudowane w sam szkielet. Najprostszym sposobem na ich użycie jest odwołanie przy pomocy statycznego wywołania którejś z metod EasyMock. Poniżej znajduje się lista dostępnych matcherów. Wartość &#8220;given&#8221; to argument przekazany w wywołaniu metody. </p>
<ul>
<li><strong>eq</strong>(X value)<br />
    Argument pasuje jeśli wyrażenie value.equals(given) zwróci true. Dostępny dla wszystkich typów prostych i obiektów.</li>
<li><strong>anyBoolean</strong>(), <strong>anyByte</strong>(), <strong>anyChar</strong>(), <strong>anyDouble</strong>(), <strong>anyFloat</strong>(), <strong>anyInt</strong>(), <strong>anyLong</strong>(), <strong>anyObject</strong>(), <strong>anyShort</strong>()<br />
    Dowolna wartość zostanie przepuszczona niezależnie od tego co będzie przekazane. Dostępny dla wszystkich typów.
</li>
<li><strong>eq</strong>(X value, X delta)<br />
    Pasuje jeśli aktualna jeśli wyrażenie given jest równe value z dokładnością do delta. Dostępne dla typów float oraz double.</li>
<li><strong>aryEq</strong>(X value)<br />
    Pasuje jeśli wyrażenie Arrays.equals(value, given) zwraca true. Dostępne dla tablic typów prostych jak i dla obiektów.</li>
<li><strong>isNull</strong>()<br />
    Pasuje jeśli given == null. Dostępne tylko dla obiektów.</li>
<li><strong>notNull</strong>()<br />
    Pasuje jeśli given != null. Dostępne tylko dla obiektów.</li>
<li><strong>same</strong>(X value)<br />
    Pasuje jeśli wyrażenie value == given jest prawdziwe. Dostępne tylko dla obiektów.</li>
<li><strong>isA</strong>(Class clazz)<br />
    Pasuje jeśli given instanceof clazz zwraca true. Given może być instancję clazz jak i pochodną.</li>
<li><strong>lt</strong>(X value), <strong>leq</strong>(X value), <strong>geq</strong>(X value), <strong>gt</strong>(X value)<br />
    Zwraca true jeśli given jest mniejsze, mniejsze równe, większe równe bądź większe niż value. Dostępne dla wszystkich numerycznych typów prostych.</li>
<li><strong>startsWith</strong>(String prefix), <strong>contains</strong>(String substring), <strong>endsWith</strong>(String suffix)<br />
    Zwraca true jeśli given  zaczyna się, zawiera bądź kończy się daną wartością. Dostępne dla argumentów typu String.</li>
<li><strong>matches</strong>(String regex), <strong>find</strong>(String regex)<br />
    Pasuje jeśli given pasuje w całości do wyrażenia/fragment pasuje. Dostępne dla argumentów typu String.</li>
<li><strong>and</strong>(X first, X second)<br />
    Zwraca true jeśli matcher first oraz second zwracają prawdę.</li>
<li><strong>or</strong>(X first, X second)<br />
    Zwraca true jeśli matcher first bądź second pasuje.</li>
<li><strong>not</strong>(X value)<br />
    Zwraca true jeśli matcher value zwrócił fałsz.</li>
</ul>
<p>Uzbrojeni w taki zestaw matcherów możemy poprawić kod testu tak by był on poprawny:</p>
<pre class="brush: java;">

public class FinderTest extends TestCase {

    public void testFind() {
        Finder mock = createMock(Finder.class);
        expect(mock.find(aryEq(new String[] {&quot;Amy&quot;, &quot;Luke&quot;}))).andReturn(
            Collections.EMPTY_LIST);
        replay(mock);

        List&lt;String&gt; list = mock.find(new String[] {&quot;Amy&quot;, &quot;Luke&quot;});
        assertTrue(list.isEmpty());
    }
}
</pre>
<p>Inny przykład:</p>
<pre class="brush: java;">
public class FinderTest extends TestCase {

    public void testFind() {
        Finder mock = createMock(Finder.class);
        expect(mock.find(&quot;Lucy&quot;, aryEq(new String[] {&quot;Amy&quot;, &quot;Luke&quot;}))).andReturn(
            Collections.EMPTY_LIST);
        replay(mock);

        List&lt;String&gt; list = mock.find(&quot;Lucy&quot;, new String[] {&quot;Amy&quot;, &quot;Luke&quot;});
        assertTrue(list.isEmpty());
    }
}
</pre>
<p>Warto zwrócić uwagę na to, że jeśli korzystamy dla matchera aby dopasować argument to musimy zrobić to dla wszystkich, inaczej poleci wyjątek:</p>
<pre class="brush: java;">
java.lang.IllegalStateException: 2 matchers expected, 1 recorded.
</pre>
<p>Stąd nasz test w końcowej postaci powinien wyglądać następująco:</p>
<pre class="brush: java;">
package org.code_house.test.mock;

import static org.easymock.EasyMock.aryEq;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.eq;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;

import java.util.Collections;
import java.util.List;

import junit.framework.TestCase;

interface Finder {
    List&lt;String&gt; find(String[] names);

    List&lt;String&gt; find(String name, String[] names);
}

public class FinderTest extends TestCase {

    public void testFind() {
        Finder mock = createMock(Finder.class);
        expect(mock.find(eq(&quot;Lucy&quot;), aryEq(new String[] {&quot;Amy&quot;, &quot;Luke&quot;}))).andReturn(
            Collections.EMPTY_LIST);
        replay(mock);

        List&lt;String&gt; list = mock.find(&quot;Lucy&quot;, new String[] {&quot;Amy&quot;, &quot;Luke&quot;});
        assertTrue(list.isEmpty());
    }
}
</pre>]]></content:encoded>
			<wfw:commentRss>http://blog.dywicki.pl/2008/11/26/testing-array-parameters-with-easymock/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JUnit. Pragmatyczne testy jednostkowe w Javie</title>
		<link>http://blog.dywicki.pl/2008/09/02/junit-pragmatyczne-testy-jednostkowe-w-javie/</link>
		<comments>http://blog.dywicki.pl/2008/09/02/junit-pragmatyczne-testy-jednostkowe-w-javie/#comments</comments>
		<pubDate>Tue, 02 Sep 2008 16:51:50 +0000</pubDate>
		<dc:creator>Łukasz Dywicki</dc:creator>
				<category><![CDATA[Framework]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Testy jednostkowe]]></category>

		<guid isPermaLink="false">http://blog.dywicki.pl/?p=129</guid>
		<description><![CDATA[Temat testów jednostkowych nie pojawiał się na tym blogu tak często jak PHP czy JAXB, jakkolwiek temat ten poruszałem w 2 notach &#8211; o testach oraz o singletonie. Tych, którzy chcieliby dowiedzieć się więcej o testach na przykładzie JUnit i Javy zapraszam się do zapoznania z bardzo dobrą pozycją na temat testów jednostkowych, z którą [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://blog.dywicki.pl/wp-content/uploads/2008/09/junit.jpg" style="text-decoration: none;" rel="lightbox"><img src="http://blog.dywicki.pl/wp-content/uploads/2008/09/junit-209x300.jpg" alt="Okładka książki" title="Okładka książki" width="209" height="300" align="left" style="margin: 10px" /></a><br />
Temat testów jednostkowych nie pojawiał się na tym blogu tak często jak <a href="http://blog.dywicki.pl/category/php"><acronym title="Pre-Hypertext Processing">PHP</acronym></a> czy <a href="http://blog.dywicki.pl/category/jaxb">JAXB</a>, jakkolwiek temat ten poruszałem w 2 notach &#8211; <a href="http://blog.dywicki.pl/2007/04/22/testy-jednostkowe/">o testach</a> oraz <a href="http://blog.dywicki.pl/2007/02/01/singleton/">o singletonie</a>.</p>
<p>Tych, którzy chcieliby dowiedzieć się więcej o testach na przykładzie <a href="http://junit.org">JUnit</a> i Javy zapraszam się do zapoznania z bardzo dobrą pozycją na temat testów jednostkowych, z którą miałem przyjemność się zetknąć.<br />
<span id="more-129"></span><br />
<a href="http://helion.pl/ksiazki/junit.htm">JUnit. Pragmatyczne testy jednostkowe w Javie</a> to tłumaczenie książki <a href="http://www.pragmaticprogrammer.com/starter_kit/utj/index.html">Pragmatic Unit Testing in Java</a> z serii <a href="http://www.pragmaticprogrammer.com/bookshelf/index.html">The Pragmatic Programmers</a>. Nie wspominam tu o tej książce jak i całej serii przypadkowo, ponieważ pragmatyzm jest główną domeną tego bloga.</p>
<p>Tytuł ten traktuje o rzeczy bardzo ważnej, jaką są bez wątpienia testy jednostkowe. Nie jest to sucha referencja opisująca możliwości <a href="http://junit.org">JUnit</a> ale przewodnik i poradnik &#8211; czyli nie tylko o tym czym testować ale po co i w jaki sposób to robić. Sam język w którymś momencie schodzi na drugi plan a ważna staje się na prawdę idea i szczytny cel, jakim jest wykluczanie błędów przed wdrożeniem aplikacji, tak by nie musiał się o nich w ogóle dowiadywać klient.</p>
<p>W książce znajduje się wiele przykładów i rozważań, pisanych lekkim językiem, całość czyta się lekko i przyjemnie. Jest to bodajże najczęściej wypożyczana pozycja z mojej domowej biblioteczki. W każdej kolejnej pracy (a troszkę ich w międzyczasie było :)) staram się komuś polecić tą pozycję i odzew jest zawsze pozytywny, co dowodzi, że praca autora włożona w tytuł była bardzo przemyślana. Z najważniejszych elementów, które zostają w książce omówione należy wymienić definiowanie warunków brzegowych, wykorzystanie &#8220;obiektów imitacji&#8221;<br />
 (ang. <em>mock objects</em>) z użyciem biblioteki <a href="http://easymock.org/">Easy Mock</a> oraz projektowanie kodu przyjaznego dla testów. Chyba wszyscy się ze mną zgodzą że są to elementy nieodzowne podczas tworzenia testów.</p>
<p>Na zakończenie przytoczę dwa akapity które najbardziej zapamiętałem z całej pozycji.</p>
<p><em>Gdyby architekci sprawdzali mosty w taki sam sposób jak większość programistów to na świeżo wybudowanym moście środkiem jezdni przejeżdżałby jeden malutki samochód w ciepły dzień, bez jakiegokolwiek wiatru i innych zakłóceń atmosferycznych.</em> (o warunkach brzegowych)</p>
<p><em>Z testami jednostkowymi jest jak ze strzyżeniem trawnika. Jeśli jest on dobrze utrzymany to jego uporządkowanie nie jest zadaniem trudnym. Jeśli jednak nasz trawnik zarośnie (w projekcie nie będzie testów jednostkowych) i pojawią się chwasty (błędy) to jego uporządkowanie (wprowadzenie testów) będzie zadaniem bardzo czasochłonnym.</em> (o filozofii testowania)</p>
<p>Koniec końców, siejąc pragmatyczną propagandę na rzecz testów :), zachęcam wszystkich do zapoznania się z opisywaną książką. Dla praktyków zawiera ona kilka trafnych spostrzeżeń a dla laików będzie znakomitym sposobem na wdrożenie się w temat testów.</p>
<p><sup>Szkic tej noty czekał na publikację ponad rok, stąd może być on troszkę nieskładny.</sup></p>]]></content:encoded>
			<wfw:commentRss>http://blog.dywicki.pl/2008/09/02/junit-pragmatyczne-testy-jednostkowe-w-javie/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Testy jednostkowe</title>
		<link>http://blog.dywicki.pl/2007/04/22/testy-jednostkowe/</link>
		<comments>http://blog.dywicki.pl/2007/04/22/testy-jednostkowe/#comments</comments>
		<pubDate>Sat, 21 Apr 2007 22:34:15 +0000</pubDate>
		<dc:creator>Łukasz Dywicki</dc:creator>
				<category><![CDATA[Ogólne]]></category>
		<category><![CDATA[Testy jednostkowe]]></category>

		<guid isPermaLink="false">http://blog.dywicki.pl/2007/04/22/testy-jednostkowe/</guid>
		<description><![CDATA[Praktyka W tym miejscu bazuję na swoim bądź co bądź skromnym doświadczeniu, które nabyłem pracując w AGI. Była to pierwsza firma, w której spotkałem się z wykorzystaniem testów jednostkowych. Pamiętam do dzisiaj walki o 70% pokrycie kodu testami. :). Nie mniej, nie robiliśmy tego tylko po to by zobaczyć zielone słupki w raporcie wygenerowanym przez [...]]]></description>
			<content:encoded><![CDATA[<h2>Praktyka</h2>
<p>W tym miejscu bazuję na swoim bądź co bądź skromnym doświadczeniu, które nabyłem pracując w <a href="http://autoguard.pl">AGI</a>. Była to pierwsza firma, w której spotkałem się z wykorzystaniem testów jednostkowych. Pamiętam do dzisiaj walki o 70% pokrycie kodu testami. :).<br />
Nie mniej, nie robiliśmy tego tylko po to by zobaczyć zielone słupki w raporcie wygenerowanym przez <a href="http://phpunit.de"><acronym title="Pre-Hypertext Processing">PHP</acronym> Unit</a>. Takie pokrycie kodu testami gwarantuje znaczne ograniczenie błędów wychodzących z czasem, głównie dlatego, że znajduje się już podczas pisania testów.<br />
<span id="more-128"></span><br />
Zasadniczo możemy wyróżnić dwa podejścia do testów &#8211; bardzo inwazyjne &#8211; projektowanie sterowane testami (ang.<em>Test Driven Development</em>), czyli opieranie się w całości na testach. Wygląda to mniej więcej w ten sposób, że tworzymy interfejs, do niego test i testujemy przy użyciu <a href="http://www.mockobjects.com/">mock objects</a> (w wolnym przekładzie można to traktować jako obiekty pozorne). Jednym z założeń jest to, że testy nie mogą się zmieniać.<br />
Drugie podejście, z którego korzystaliśmy to, w sumie nienazwane, wspomaganie testami. W skrócie, pisząc klasę piszemy również test do niej, tak by na bieżąco sprawdzać poprawność działania kodu. Jeśli zmieni się interfejs etc, testy również mogą się zmienić.</p>
<h2>Korzyści</h2>
<h3>Nie pozwól błędom zawładnąć Twoją aplikacją</h3>
<p>Tak jak wcześniej wspominałem korzyści, które niosą ze sobą testy jednostkowe to wyłapywanie błędów nim mają szansę coś popsuć. Ile razy szukałeś błędu, który był zakopany tak niewiarygodnie głęboko zakopany, że jego lokalizacja zajęła Ci kilka dni? Ile razy po prostu zrezygnowałeś z walki stosując jakąś brudną protezę? Testy, które sprawdzają niewielkie fragmenty kodu (po prostu pojedyncze metody) lokalizują błędy z dużą dokładnością. Szukanie błędu gdy wiadomo gdzie on tkwi jest znacznie łatwiejsze i mniej czasochłonne. Zwykle to lokalizacja miejsca, gdzie błąd powstaje zajmuje więcej czasu niż jego naprawienie. Jedna metoda, która generuje błędny wynik prowadzi do błędnej implementacji kolejnej, ta z kolei determinuje błąd w innym algorytmie.</p>
<h3>Łatwiejszy refaktoring i wprowadzanie zmian w kodzie</h3>
<p>Refaktoryzacja ma to do siebie, że źle przeprowadzona, a co gorsza nie sprawdzona potrafi zrodzić spore zamieszanie. Testy jednostkowe pozwalają sprawdzić czy zmiany, które wprowadziliśmy w celu usprawnienia kodu nie niosą ze sobą błędów.<br />
Często zmiany, które wprowadzamy nie mogą być nazwane refaktoryzacją, po prostu dodajemy spory fragment kodu, który może ingerować już w istniejącym. Wybitnym przykładem mogą być tu aspekty (najprościej można to określić jako modyfikowanie zachowania kodu z zewnątrz). Innym po prostu poszerzenie implementacji jakiejś klasy pomocniczej o jedną metodę i na prawdę drobna zmiana w dwóch warunkach istniejącej. Czy masz pewność, że Twój kod działa? Zazwyczaj tak, bo testujesz go &#8220;manualnie&#8221;, ale czy wiesz, jaki wpływ mają Twoje zmiany na inne fragmenty aplikacji? Być może zmieniona metoda generowała w pewnych okolicznościach błędny wynik, który stał się początkiem wspomnianej lawiny?</p>
<h3>Praca w grupie</h3>
<p>Testy są szczególnie ważne gdy nad kodem pracuje cały zespół zapanowanie nad całością przedsięwzięcia wymaga wielkiego zaangażowania. Można je ograniczyć wprowadzając konieczność sprawdzania kodu pod kontem jego spójności z pozostałymi fragmentami aplikacji (akapit wyżej). To, że kod działa u Ciebie, nie znaczy, że zadziała u kogoś innego. Są różne platformy sprzętowe, jeszcze różniejsze konfiguracje środowisk. Czy jesteś w stanie zagwarantować, że kod bazujący na jakiejś strukturze katalogów zadziała? Czy zastanawiałeś się jak zareaguje aplikacja gdy jest uruchomiona ze złą konfiguracją? Zapewnij sobie neutralne środowisko testowym, nieskażone niczyim IDE by być pewnym, że to zadziała też u klienta jak i prezesa.</p>
<h3>Automatyzacja</h3>
<p>Automatyzacja całego procesu jest ważna. Nikt nie będzie siedział non stop i sprawdzał co godzina czy testy są ok bądź się wywalają. Nikt nie ma na to czasu i pieniędzy. Kierownik projektu ma na głowie więcej rzeczy niż tylko testy a programiści &#8220;robią swoje&#8221;. Nikt nie chce uruchamiać testów, niech zrobi to zatem maszyna. Maszyna, na której będzie stało oddzielne, gołe środowisko specjalnie pod testy. Automat pobierze aktualną wersję kodu i uruchomi testy do niego. Może robić to co godzinę bądź co dwie, ale najlepiej by robił to po każdej zmianie w repozytorium. Programista to zwierz leniwy i zdarza mu się zapomnieć o uruchomieniu testów. Przypomnienie mu o nich przez automat będzie milsze niż reprymenda dwa tygodnie po tym, jak aplikacja przestała działać u wszystkich i znaleziono winnego (vide kozła ofiarnego).</p>
<h3>Redukcja kosztów</h3>
<p>Jak to określił <a href="http://agileweb.org">Ross</a>, testy to jeden ze sposobów na wyprzedzenie kosztów, swoistego rodzaju zapłata dzierżawy. Tracimy czas (pojęcie względne) inwestując w pisanie testów, ale zyskujemy z jego biegiem, ponieważ kod naszej aplikacji po prostu działa. Nie musi nad nim czuwać sztab testerów, którzy klikają i zaznaczają w formularzach &#8220;to nie działa&#8221; z opisem typu &#8220;pole &#8216;nazwa firmy&#8217; jest ignorowane przy próbie zmiany jego wartości&#8221;. Wskazanie miejsc, gdzie rodzi się błąd nie wydaje się trudne. Albo niepodpięte mapowanie do pola, albo źle wygenerowane zapytanie. Banał. Ale spytaj kogoś, kto powie od razu który fragment kodu to robi? Sytuacja nie jest najgorsza, wykryli ją testerzy, ale bywają gorsze, znacznie gorsze. <strong>To, że kod się kompiluje nie znaczy, że działa</strong>.</p>
<h2>Studium pewnego błędu</h2>
<p>Załóżmy, że aplikacja działa od 3 miesięcy w środowisku produkcyjnym, u klienta. Nagle okazuje się, że to samo pole nie może zawierać apostrofów, ponieważ powstaje błąd zapytania <acronym title="Structured Query Language">SQL</acronym>. Inna sytuacja &#8211; dorzucenie &#038; w nazwie powoduje błąd w wyświetlaniu strony. Wpisanie specyficznej wartości w formularzu powoduje pokazanie się białej strony. Esteci się cieszą, ale klienci już nie. Padają gromy ze strony klienta. Obrywają wszyscy od góry do dołu. Warto poświęcić czas na to by mieć komfortowe warunki pracy, z minimalną ilością negatywnych emocji i tarć na linii Ty &#8211; Twój zwierzchnik.<br />
Wyeliminowanie błędu pojawiającego się u klienta jest drogie a koszt jest wprost proporcjonalny do ilości klientów. Na błędach tracą wszyscy. Firma traci pieniądze, ponieważ programista musi zlokalizować i naprawić błąd. Programista traci werwę. Nikt z nas nie lubi babrać się w czyimś kodzie, nie wiadomo jaki by on nie był, w poszukiwaniu jakiejś niedoróbki. Jednak najgorsza może być <strong>strata wizerunku</strong>. Na rynku jest pełno firm. Czy może poszczycić się Twoja? Wszyscy kochają jakość i wszyscy się nią chwalą, dopóki nie dojdzie do konfrontacji z rzeczywistością. Zadbaj by Twój produkt był dostarczony z minimalną ilością błędów, a możesz liczyć na to, że klient wróci i być może pociągnie za sobą swoich partnerów biznesowych.</p>
<h3>Zaproszenie do dyskusji</h3>
<p>Na końcu pragnę zachęcić wszystkich do zadawania pytań jak i dzielenia się swoimi doświadczeniami. Jakie są Twoje doświadczenia z testami jednostkowymi? W jaki sposób przebiegało ich wdrożenie? Czy jesteś sceptycznie nastawiony? Może jesteś przeciwko? To tylko część z tematów, które możemy poruszyć.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.dywicki.pl/2007/04/22/testy-jednostkowe/feed/</wfw:commentRss>
		<slash:comments>23</slash:comments>
		</item>
	</channel>
</rss>

