Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00009 000552 24504980 na godz. na dobę w sumie
TDD. Programowanie w Javie sterowane testami - ebook/pdf
TDD. Programowanie w Javie sterowane testami - ebook/pdf
Autor: , Liczba stron: 256
Wydawca: Helion Język publikacji: polski
ISBN: 978-83-283-2342-1 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> programowanie >> java - programowanie
Porównaj ceny (książka, ebook (-45%), audiobook).
Programowanie sterowane testami (ang. test-driven development — TDD) nie jest nową metodyką. Jej praktyczne zastosowanie pozwala na rozwiązanie wielu problemów związanych z procesami rozwijania i wdrażania oprogramowania. Mimo ogromnych zalet, programowanie sterowane testami nie jest zbyt popularne wśród programistów. Wynika to z tego, że techniki TDD nie są łatwe do opanowania. Choć teoretyczne podstawy wydają się logiczne i zrozumiałe, nabranie wprawy w stosowaniu TDD wymaga długiej praktyki.

Książka, którą trzymasz w ręce, została napisana przez programistów dla programistów. Jej celem jest przekazanie podstaw TDD i omówienie najważniejszych praktyk związanych z tą metodyką, a przede wszystkim — nauczenie praktycznego stosowania TDD w pracy. Autorzy nie ukrywają, że nabranie biegłości w takim programowaniu wymaga sporo wysiłku, jednak korzyści płynące z metodyki TDD są znaczne: skrócenie czasu wprowadzania produktów na rynek, łatwiejsza refaktoryzacja, a także wyższa jakość tworzonych projektów. Z tą książką dogłębnie zrozumiesz metodykę TDD i uzyskasz wystarczającą pewność siebie, by z powodzeniem stosować to podejście w trakcie programowania aplikacji w Javie.

Dzięki tej książce:

Programowanie sterowane testami to metodyka dla prawdziwych profesjonalistów!

Znajdź podobne książki Ostatnio czytane w tej kategorii

Darmowy fragment publikacji:

Tytuł oryginału: Test-Driven Java Development Tłumaczenie: Tomasz Walczak ISBN: 978-83-283-2341-4 Copyright © 2015 Packt Publishing First published in the English language under the title „Test-Driven Java Development — (9781783987429)”. Polish edition copyright © 2015 by Helion SA. All rights reserved. All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording or by any information storage retrieval system, without permission from the Publisher. Wszelkie prawa zastrzeżone. Nieautoryzowane rozpowszechnianie całości lub fragmentu niniejszej publikacji w jakiejkolwiek postaci jest zabronione. Wykonywanie kopii metodą kserograficzną, fotograficzną, a także kopiowanie książki na nośniku filmowym, magnetycznym lub innym powoduje naruszenie praw autorskich niniejszej publikacji. Wszystkie znaki występujące w tekście są zastrzeżonymi znakami firmowymi bądź towarowymi ich właścicieli. Autor oraz Wydawnictwo HELION dołożyli wszelkich starań, by zawarte w tej książce informacje były kompletne i rzetelne. Nie biorą jednak żadnej odpowiedzialności ani za ich wykorzystanie, ani za związane z tym ewentualne naruszenie praw patentowych lub autorskich. Autor oraz Wydawnictwo HELION nie ponoszą również żadnej odpowiedzialności za ewentualne szkody wynikłe z wykorzystania informacji zawartych w książce. Wydawnictwo HELION ul. Kościuszki 1c, 44-100 GLIWICE tel. 32 231 22 19, 32 230 98 63 e-mail: helion@helion.pl WWW: http://helion.pl (księgarnia internetowa, katalog książek) Pliki z przykładami omawianymi w książce można znaleźć pod adresem: ftp://ftp.helion.pl/przyklady/tddpro.zip Drogi Czytelniku! Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres http://helion.pl/user/opinie/tddpro Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję. Printed in Poland. • Kup książkę • Poleć książkę • Oceń książkę • Księgarnia internetowa • Lubię to! » Nasza społeczność Spis tre(cid:258)ci O autorach O recenzentach Przedmowa Rozdzia(cid:239) 1. Dlaczego powiniene(cid:258) zainteresowa(cid:202) si(cid:218) programowaniem sterowanym testami? Dlaczego TDD? Wprowadzenie do TDD Czerwone, zielone, refaktoryzacja Liczy si(cid:218) szybko(cid:258)(cid:202) To nie testy s(cid:200) najwa(cid:285)niejsze Przeprowadzanie testów Testy funkcjonalne Testy strukturalne Ró(cid:285)nica mi(cid:218)dzy sprawdzaniem jako(cid:258)ci a zapewnianiem jako(cid:258)ci Lepsze testy Symulowanie dzia(cid:239)a(cid:241) Wykonywalna dokumentacja Brak konieczno(cid:258)ci debugowania Podsumowanie Rozdzia(cid:239) 2. Narz(cid:218)dzia, platformy i (cid:258)rodowiska System Git Maszyny wirtualne Vagrant Docker Narz(cid:218)dzia do budowania kodu (cid:165)rodowisko IDE Przyk(cid:239)adowy projekt ze (cid:258)rodowiska IDEA 9 11 13 17 18 19 20 21 21 22 22 23 24 24 25 25 27 28 29 30 30 30 33 34 36 36 Poleć książkęKup książkę Spis tre(cid:286)ci Platformy do przeprowadzania testów jednostkowych JUnit TestNG Hamcrest i AssertJ Hamcrest AssertJ Narz(cid:218)dzia do okre(cid:258)lania pokrycia kodu testami JaCoCo Platformy do tworzenia zast(cid:218)pników Mockito EasyMock Dodatkowe mo(cid:285)liwo(cid:258)ci atrap Testowanie interfejsu u(cid:285)ytkownika Platformy do testowania stron WWW Selenium Selenide Programowanie sterowane zachowaniami JBehave Cucumber Podsumowanie Rozdzia(cid:239) 3. „Czerwone, zielone, refaktoryzacja” — od pora(cid:285)ki, przez sukces, do doskona(cid:239)o(cid:258)ci Przygotowywanie (cid:258)rodowiska z systemem Gradle i narz(cid:218)dziem JUnit Tworzenie w (cid:258)rodowisku IntelliJ IDEA projektu wykorzystuj(cid:200)cego system Gradle i Jav(cid:218) „Czerwone, zielone, refaktoryzacja” Napisz test Uruchom wszystkie testy i upewnij si(cid:218), (cid:285)e ostatni ko(cid:241)czy si(cid:218) niepowodzeniem Napisz kod rozwi(cid:200)zania Wykonaj wszystkie testy Przeprowad(cid:283) refaktoryzacj(cid:218) Powtórz ca(cid:239)y cykl Wymagania dotycz(cid:200)ce programu do gry w kó(cid:239)ko i krzy(cid:285)yk Pisanie programu do gry w kó(cid:239)ko i krzy(cid:285)yk Wymaganie nr 1 Wymaganie nr 2 Wymaganie nr 3 Wymaganie nr 4 Pokrycie kodu testami Dodatkowe (cid:202)wiczenia Podsumowanie 4 36 38 40 42 42 44 44 45 46 48 50 51 52 52 52 54 55 56 58 60 61 62 62 65 65 66 66 66 67 67 67 68 68 74 77 83 85 86 86 Poleć książkęKup książkę Spis tre(cid:286)ci Rozdzia(cid:239) 4. Testy jednostkowe. Koncentrowanie si(cid:218) na wykonywanym zadaniu, a nie na tym, co ju(cid:285) zosta(cid:239)o zrobione Testy jednostkowe Czym s(cid:200) testy jednostkowe? Po co stosowa(cid:202) testy jednostkowe? Refaktoryzacja kodu Dlaczego nie ograniczy(cid:202) si(cid:218) do stosowania samych testów jednostkowych? Testy jednostkowe w TDD Platforma TestNG Adnotacja @Test Adnotacje @BeforeSuit, @BeforeTest, @BeforeGroups, @AfterGroups, @AfterTest i @AfterSuit Adnotacje @BeforeClass i @AfterClass Adnotacje @BeforeMethod i @AfterMethod Argument w adnotacji @Test(enable = false) Argument w adnotacji @Test(expectedExceptions = NazwaKlasy.class) Podsumowanie porównania platform TestNG i JUnit Wymagania dotycz(cid:200)ce zdalnie sterowanego statku Pisanie kodu do zdalnego sterowania statkiem Przygotowywanie projektu Klasy pomocnicze Wymaganie nr 1 Wymaganie nr 2 Wymaganie nr 3 Wymaganie nr 4 Wymaganie nr 5 Wymaganie nr 6 Podsumowanie Rozdzia(cid:239) 5. Projekt. Je(cid:258)li czego(cid:258) nie da si(cid:218) przetestowa(cid:202), projekt jest nieprawid(cid:239)owy Dlaczego projekt ma znaczenie? Zasady projektowe Czwórki Wymagania Testowanie ostatniej wersji programu do gry Czwórki Wymaganie nr 1 Wymaganie nr 2 Wymaganie nr 3 Wymaganie nr 4 Wymaganie nr 5 Wymaganie nr 6 Wymaganie nr 7 Wymaganie nr 8 89 90 90 91 91 91 93 94 94 95 95 95 96 96 96 97 97 97 99 100 103 105 106 109 113 113 115 116 116 118 119 119 120 121 121 122 124 124 125 126 5 Poleć książkęKup książkę Spis tre(cid:286)ci Program do gry w Czwórki napisany za pomoc(cid:200) TDD Hamcrest Wymaganie nr 1 Wymaganie nr 2 Wymaganie nr 3 Wymaganie nr 4 Wymaganie nr 5 Wymaganie nr 6 Wymaganie nr 7 Wymaganie nr 8 Podsumowanie Rozdzia(cid:239) 6. Eliminowanie zewn(cid:218)trznych zale(cid:285)no(cid:258)ci za pomoc(cid:200) atrap Tworzenie zast(cid:218)pników Po co tworzy(cid:202) atrapy? Terminologia Obiekty pe(cid:239)ni(cid:200)ce funkcj(cid:218) atrap Platforma Mockito Wymagania dotycz(cid:200)ce drugiej wersji programu do gry w kó(cid:239)ko i krzy(cid:285)yk Rozwijanie drugiej wersji programu do gry w kó(cid:239)ko i krzy(cid:285)yk Wymaganie nr 1 Wymaganie nr 2 Testy integracyjne Oddzielanie testów od siebie Test integracyjny Podsumowanie Rozdzia(cid:239) 7. Programowanie sterowane zachowaniami — wspó(cid:239)praca w ramach ca(cid:239)ego zespo(cid:239)u Ró(cid:285)ne specyfikacje Dokumentacja Dokumentacja dla programistów Dokumentacja dla nieprogramistów Programowanie sterowane zachowaniami Narracja Scenariusze Historia BDD dotycz(cid:200)ca ksi(cid:218)garni JBehave Klasa Runner dla platformy JBehave Niegotowe kroki Selenium i Selenide Kroki w platformie JBehave Ostateczne sprawdzanie poprawno(cid:258)ci Podsumowanie 6 127 128 128 129 132 133 135 135 137 138 140 141 142 143 144 144 145 146 146 147 158 164 165 166 168 169 170 170 171 172 173 173 175 176 179 179 181 183 184 190 191 Poleć książkęKup książkę Spis tre(cid:286)ci Rozdzia(cid:239) 8. Refaktoryzacja zastanego kodu w celu „odm(cid:239)odzenia” go Zastany kod Przyk(cid:239)adowy zastany kod (cid:109)wiczenie kata Kata dotycz(cid:200)ce zastanego kodu Opis Komentarze techniczne Dodawanie nowych funkcji Testy funkcjonalne i testy badawcze Wst(cid:218)pne analizy Stosowanie algorytmu modyfikowania zastanego kodu Wyodr(cid:218)bnianie i przes(cid:239)anianie wywo(cid:239)ania Eliminowanie nadu(cid:285)ywania typów podstawowych w przypadku statusu zwracanego jako warto(cid:258)(cid:202) typu int Podsumowanie Rozdzia(cid:239) 9. Prze(cid:239)(cid:200)czniki funkcji — wdra(cid:285)anie cz(cid:218)(cid:258)ciowo uko(cid:241)czonych funkcji w (cid:258)rodowisku produkcyjnym Ci(cid:200)g(cid:239)a integracja, ci(cid:200)g(cid:239)e dostarczanie i ci(cid:200)g(cid:239)e wdra(cid:285)anie Prze(cid:239)(cid:200)czniki funkcji Przyk(cid:239)ad zastosowania prze(cid:239)(cid:200)cznika funkcji Pisanie kodu us(cid:239)ugi wyznaczaj(cid:200)cej liczby Fibonacciego Korzystanie z silnika obs(cid:239)ugi szablonów Podsumowanie Rozdzia(cid:239) 10. (cid:146)(cid:200)czenie wszystkich informacji TDD w pigu(cid:239)ce Najlepsze praktyki Konwencje nazewnicze Procesy Praktyki zwi(cid:200)zane z pisaniem kodu Narz(cid:218)dzia To tylko pocz(cid:200)tek To nie musi by(cid:202) koniec Skorowidz 193 194 194 204 204 205 205 205 205 206 210 216 220 223 225 226 228 229 233 236 240 241 241 243 243 245 247 251 252 252 253 7 Poleć książkęKup książkę Poleć książkęKup książkę 4 Testy jednostkowe. Koncentrowanie si(cid:218) na wykonywanym zadaniu, a nie na tym, co ju(cid:285) zosta(cid:239)o zrobione „Je(cid:258)li chcesz utworzy(cid:202) co(cid:258) wyj(cid:200)tkowego, twój umys(cid:239) musi by(cid:202) nieustannie skoncentrowany na najdrobniejszych szczegó(cid:239)ach”. — Giorgio Armani Zgodnie z wcze(cid:258)niejsz(cid:200) obietnic(cid:200) w ka(cid:285)dym rozdziale opisana zostanie inna platforma do testowania kodu napisanego w Javie. Ten rozdzia(cid:239) nie jest pod tym wzgl(cid:218)dem wyj(cid:200)tkiem. Do budowania specyfikacji pos(cid:239)u(cid:285)y tu platforma TestNG. W poprzednim rozdziale zastosowano procedur(cid:218) czerwone, zielone, refaktoryzacja. Wykorzy- stano testy jednostkowe bez dok(cid:239)adnego wyt(cid:239)umaczenia, jak te testy dzia(cid:239)aj(cid:200) w kontek(cid:258)cie TDD. Tutaj na podstawie informacji z poprzedniego rozdzia(cid:239)u szczegó(cid:239)owo wyja(cid:258)niono, czym s(cid:200) testy jednostkowe i jakie jest ich miejsce w procesie budowania oprogramowania za pomoc(cid:200) TDD. Poleć książkęKup książkę TDD. Programowanie w Javie sterowane testami Celem tego rozdzia(cid:239)u jest pokazanie, jak skoncentrowa(cid:202) si(cid:218) na obecnie rozwijanej jednostce i jak ignorowa(cid:202) lub izolowa(cid:202) wcze(cid:258)niej uko(cid:241)czone elementy. Gdy ju(cid:285) opanujesz wiedz(cid:218) na temat platformy TestNG i testów jednostkowych, przejdziesz bezpo(cid:258)rednio do wymaga(cid:241) zwi(cid:200)zanych z nast(cid:218)pn(cid:200) aplikacj(cid:200) i przyst(cid:200)pisz do pisania kodu. Oto zagadnienia omówione w tym rozdziale: (cid:81) testy jednostkowe, (cid:81) testy jednostkowe w TDD, (cid:81) platforma TestNG, (cid:81) wymagania dotycz(cid:200)ce zdalnie sterowanego statku, (cid:81) pisanie kodu zdalnie sterowanego statku, (cid:81) podsumowanie. Testy jednostkowe Cz(cid:218)ste testy r(cid:218)czne s(cid:200) akceptowalne tylko w trakcie pracy nad najmniejszymi systemami. Jedyny sposób na zast(cid:200)pienie testów r(cid:218)cznych to zastosowanie testów automatycznych. S(cid:200) one jedyn(cid:200) skuteczn(cid:200) metod(cid:200) pozwalaj(cid:200)c(cid:200) skróci(cid:202) czas i zmniejszy(cid:202) koszty budowania, wdra(cid:285)ania i konserwowania aplikacji. Je(cid:258)li chcesz móc efektywnie zarz(cid:200)dza(cid:202) aplikacjami, nie- zwykle istotne jest, by kod rozwi(cid:200)zania i kod testów by(cid:239)y jak najprostsze. Prostota jest jedn(cid:200) z podstawowych warto(cid:258)ci programowania ekstremalnego (ang. eXtreme Programming — XP; http://www.extremeprogramming.org/rules/simple.html) oraz bardzo wa(cid:285)nym aspektem TDD i programowania w ogóle. Najcz(cid:218)(cid:258)ciej prostot(cid:218) zapewnia si(cid:218) dzi(cid:218)ki podzia(cid:239)owi rozwi(cid:200)zania na ma(cid:239)e jednostki. W Javie tymi jednostkami s(cid:200) metody. Poniewa(cid:285) s(cid:200) one najmniejsze, pozwalaj(cid:200) najszybciej uzyska(cid:202) informacje zwrotne. Dlatego to w(cid:239)a(cid:258)nie metodom po(cid:258)wi(cid:218)ca si(cid:218) najwi(cid:218)cej czasu w trakcie my(cid:258)lenia o rozwi(cid:200)zaniu i pracy nad nim. Odpowiednikiem metod z kodu roz- wi(cid:200)zania s(cid:200) testy jednostkowe, które powinny stanowi(cid:202) najwi(cid:218)kszy procent wszystkich testów. Czym s(cid:200) testy jednostkowe? Testy jednostkowe to technika wymuszaj(cid:200)ca testowanie ma(cid:239)ych, pojedynczych i odizolowanych jednostek kodu. Tymi jednostkami s(cid:200) zwykle metody, cho(cid:202) czasem u(cid:285)ywane s(cid:200) klasy, a nawet ca(cid:239)e aplikacje. Aby napisa(cid:202) test jednostkowy, badany kod trzeba odizolowa(cid:202) od reszty aplikacji. Najlepiej, gdy izolacja ta jest wbudowana w kod lub gdy mo(cid:285)na j(cid:200) osi(cid:200)gn(cid:200)(cid:202) za pomoc(cid:200) atrap (wi(cid:218)cej o atrapach dowiesz si(cid:218) z rozdzia(cid:239)u 6., „Eliminowanie zewn(cid:218)trznych zale(cid:285)no(cid:258)ci za po- moc(cid:200) atrap”). Je(cid:258)li testy jednostkowe sprawdzanej metody wykraczaj(cid:200) poza granice danej jednostki, staj(cid:200) si(cid:218) testami integracyjnymi. W takich testach trudniej jest ustali(cid:202), które frag- menty kodu s(cid:200) sprawdzane. Gdy test ko(cid:241)czy si(cid:218) niepowodzeniem, mo(cid:285)liwy zasi(cid:218)g wyst(cid:200)pienia usterki ro(cid:258)nie, przez co znalezienie (cid:283)ród(cid:239)a problemu staje si(cid:218) trudniejsze. 90 Poleć książkęKup książkę Rozdzia(cid:225) 4. • Testy jednostkowe Po co stosowa(cid:202) testy jednostkowe? Standardowe pytanie, zadawane zw(cid:239)aszcza w firmach, gdzie wykorzystuje si(cid:218) g(cid:239)ównie testy r(cid:218)czne, brzmi: „Dlaczego powinni(cid:258)my stosowa(cid:202) testy jednostkowe zamiast testów funkcjonalnych lub integracyjnych?”. Jest to b(cid:239)(cid:218)dnie postawione pytanie. Testy jednostkowe nie zast(cid:218)puj(cid:200) testów innego rodzaju, a jedynie pozwalaj(cid:200) ograniczy(cid:202) zakres pozosta(cid:239)ych testów. Testy jednostkowe z natury pisze si(cid:218) (cid:239)atwiej i szybciej ni(cid:285) testy innego typu. Pozwala to ograniczy(cid:202) koszty i szybciej wprowadzi(cid:202) produkt na rynek. Poniewa(cid:285) takie testy mo(cid:285)na szybko pisa(cid:202) i uruchamia(cid:202), znacznie szybciej wykrywane s(cid:200) te(cid:285) problemy. Im szybciej wykryjesz problem, tym ta(cid:241)sze b(cid:218)dzie jego rozwi(cid:200)zanie. B(cid:239)(cid:200)d wykryty kilka minut po jego pope(cid:239)nieniu jest znacznie (cid:239)atwiejszy do na- prawienia ni(cid:285) ta sama usterka znaleziona po kilku dniach, tygodniach czy miesi(cid:200)cach. Refaktoryzacja kodu Refaktoryzacja kodu to proces modyfikowania struktury istniej(cid:200)cego kodu bez zmiany jego dzia(cid:239)ania. Celem refaktoryzacji jest ulepszenie ju(cid:285) napisanego kodu. Poprawki mo(cid:285)na wpro- wadza(cid:202) z wielu ró(cid:285)nych powodów. Mo(cid:285)liwe, (cid:285)e chcesz zwi(cid:218)kszy(cid:202) czytelno(cid:258)(cid:202) kodu, zmniej- szy(cid:202) jego z(cid:239)o(cid:285)ono(cid:258)(cid:202), u(cid:239)atwi(cid:202) konserwacj(cid:218), ograniczy(cid:202) koszty rozbudowywania rozwi(cid:200)zania i tak dalej. Niezale(cid:285)nie od przyczyn refaktoryzacji g(cid:239)ównym jej celem zawsze jest ulepszenie kodu. Skutkiem realizacji tego celu jest zmniejszenie d(cid:239)ugu technicznego, co pozwala ograni- czy(cid:202) ilo(cid:258)(cid:202) pracy, któr(cid:200) trzeba wykona(cid:202) z powodu nieoptymalnego projektu i kodu lub niedo- skona(cid:239)ej architektury. Refaktoryzacja zwykle polega na wprowadzaniu zestawu drobnych zmian bez modyfikowania po(cid:285)(cid:200)danego dzia(cid:239)ania kodu. Ograniczenie zakresu zmian w trakcie refaktoryzacji pozwala za- chowa(cid:202) pewno(cid:258)(cid:202), (cid:285)e poprawki nie naruszy(cid:239)y dzia(cid:239)ania istniej(cid:200)cych funkcji. Jedyny sposób na uzyskanie tej pewno(cid:258)ci polega na zastosowaniu zautomatyzowanych testów. Jedn(cid:200) z istotnych zalet testów jednostkowych jest to, (cid:285)e s(cid:200) najlepszym narz(cid:218)dziem wspoma- gaj(cid:200)cym przeprowadzanie refaktoryzacji. Refaktoryzacja jest zbyt ryzykowna, je(cid:258)li nie istniej(cid:200) zautomatyzowane testy potwierdzaj(cid:200)ce, (cid:285)e aplikacja wci(cid:200)(cid:285) dzia(cid:239)a zgodnie z oczekiwaniami. Cho(cid:202) do zapewnienia pokrycia kodu testami potrzebnego w trakcie refaktoryzacji mo(cid:285)na wy- korzysta(cid:202) testy dowolnego typu, zwykle tylko testy jednostkowe pozwalaj(cid:200) zapewni(cid:202) po(cid:285)(cid:200)dany poziom szczegó(cid:239)owo(cid:258)ci. Dlaczego nie ograniczy(cid:202) si(cid:218) do stosowania samych testów jednostkowych? Mo(cid:285)liwe, (cid:285)e zastanawiasz si(cid:218), czy testy jednostkowe mog(cid:200) zaspokoi(cid:202) wszystkie Twoje potrzeby zwi(cid:200)zane z testami. Niestety, nie mog(cid:200). Cho(cid:202) testy jednostkowe zwykle pozwalaj(cid:200) uwzgl(cid:218)dni(cid:202) wi(cid:218)kszo(cid:258)(cid:202) takich potrzeb, testy funkcjonalne i integracyjne te(cid:285) powinny by(cid:202) nieod(cid:239)(cid:200)czn(cid:200) cz(cid:218)(cid:258)ci(cid:200) Twojego zestawu narz(cid:218)dzi. 91 Poleć książkęKup książkę TDD. Programowanie w Javie sterowane testami Inne typy testów s(cid:200) omówione szczegó(cid:239)owo w dalszych rozdzia(cid:239)ach. Na razie warto zwróci(cid:202) uwag(cid:218) na kilka wa(cid:285)nych ró(cid:285)nic mi(cid:218)dzy poszczególnymi rodzajami testów. (cid:81) Testy jednostkowe s(cid:239)u(cid:285)(cid:200) do sprawdzania niewielkich jednostek funkcyjnych. W Javie tymi jednostkami s(cid:200) metody. Wszystkie zewn(cid:218)trzne zale(cid:285)no(cid:258)ci zwi(cid:200)zane z wywo(cid:239)aniami innych klas, metod lub baz danych powinny by(cid:202) obs(cid:239)ugiwane w pami(cid:218)ci za pomoc(cid:200) atrap, namiastek, „szpiegów” oraz zast(cid:218)pników typu fake i dummy. Gerard Meszaros wymy(cid:258)li(cid:239) ogólne okre(cid:258)lenie „dublery u(cid:285)ywane w czasie testów” (ang. test doubles), które obejmuje wszystkie wymienione techniki (zobacz opis na stronie http://en.wikipedia.org/wiki/Test_double). Testy jednostkowe s(cid:200) proste, (cid:239)atwo si(cid:218) je pisze i szybko wykonuje. Zwykle stanowi(cid:200) najwi(cid:218)ksz(cid:200) cz(cid:218)(cid:258)(cid:202) w zestawie testów. (cid:81) Testy funkcjonalne i akceptacyjne s(cid:239)u(cid:285)(cid:200) do sprawdzania, czy rozwijana aplikacja dzia(cid:239)a poprawnie jako ca(cid:239)o(cid:258)(cid:202). Cho(cid:202) te dwa typy testów ró(cid:285)ni(cid:200) si(cid:218) od siebie, u(cid:285)ywa si(cid:218) ich w tym samym celu. W odró(cid:285)nieniu od testów jednostkowych, które sprawdzaj(cid:200) wewn(cid:218)trzn(cid:200) jako(cid:258)(cid:202) kodu, testy funkcjonalne i akceptacyjne maj(cid:200) zapewnia(cid:202), (cid:285)e system pracuje prawid(cid:239)owo z perspektywy klienta lub u(cid:285)ytkownika. Zazwyczaj liczba tych testów jest mniejsza ni(cid:285) liczba testów jednostkowych. Wynika to z du(cid:285)ego nak(cid:239)adu kosztów i wysi(cid:239)ku, jaki trzeba w(cid:239)o(cid:285)y(cid:202) w pisanie testów tych dwóch typów i ich wykonywanie. (cid:81) Testy integracyjne maj(cid:200) sprawdza(cid:202), czy odr(cid:218)bne jednostki, modu(cid:239)y, aplikacje, a nawet ca(cid:239)e systemy s(cid:200) prawid(cid:239)owo zintegrowane ze sob(cid:200). Za(cid:239)ó(cid:285)my, (cid:285)e korzystasz z frontonu, który na zapleczu u(cid:285)ywa interfejsu API, a ten z kolei komunikuje si(cid:218) z baz(cid:200) danych. Testy integracyjne pozwol(cid:200) sprawdzi(cid:202), czy te trzy odr(cid:218)bne komponenty systemu s(cid:200) zintegrowane ze sob(cid:200) i mog(cid:200) si(cid:218) mi(cid:218)dzy sob(cid:200) komunikowa(cid:202). Poniewa(cid:285) wiadomo, (cid:285)e jednostki dzia(cid:239)aj(cid:200) poprawnie i (cid:285)e wszystkie testy funkcjonalne oraz akceptacyjne zako(cid:241)czy(cid:239)y si(cid:218) powodzeniem, testy integracyjne zwykle stanowi(cid:200) najmniejsz(cid:200) grup(cid:218) spo(cid:258)ród trzech omawianych kategorii testów. Wynika to z tego, (cid:285)e testy integracyjne maj(cid:200) tylko zapewnia(cid:202), (cid:285)e wszystkie elementy poprawnie ze sob(cid:200) wspó(cid:239)pracuj(cid:200). Widoczna na rysunku 4.1 piramida testów pokazuje, (cid:285)e testów jednostkowych powinno by(cid:202) znacznie wi(cid:218)cej ni(cid:285) testów z wy(cid:285)szych poziomów (testów interfejsu u(cid:285)ytkownika, testów inte- gracyjnych i tak dalej). Z czego to wynika? Testy jednostkowe s(cid:200) znacznie ta(cid:241)sze do pisania, szybsze do uruchamiania i ponadto zapewniaj(cid:200) wy(cid:285)sze pokrycie kodu. Pomy(cid:258)l na przyk(cid:239)ad o funkcji rejestrowania si(cid:218) u(cid:285)ytkownika. Nale(cid:285)y sprawdzi(cid:202), co si(cid:218) stanie, gdy pole na nazw(cid:218) u(cid:285)ytkownika jest puste, gdy pole na has(cid:239)o jest puste, gdy nazwa u(cid:285)ytkownika lub has(cid:239)o ma z(cid:239)y format, gdy dany u(cid:285)ytkownik ju(cid:285) istnieje i tak dalej. Dla tej jednej funkcji mo(cid:285)na napisa(cid:202) dziesi(cid:200)tki, a nawet setki testów. Pisanie i uruchamianie takich testów z poziomu interfejsu u(cid:285)ytkownika bywa bardzo kosztowne. Budowanie tego rodzaju testów jest czasoch(cid:239)onne, a ich wykonywanie zajmuje du(cid:285)o czasu. Natomiast przeprowadzenie testu jednostkowego z u(cid:285)yciem metody, która sprawdza poprawno(cid:258)(cid:202) omawianej funkcji, wygl(cid:200)da inaczej. Test jest wtedy prosty, dzi(cid:218)ki czemu mo(cid:285)na go szybko napisa(cid:202) i uruchomi(cid:202). Je(cid:258)li wszystkie sytuacje s(cid:200) uwzgl(cid:218)dnione w testach jednostkowych, wystarczy wykona(cid:202) jeden test integracyjny, sprawdzaj(cid:200)cy, czy inter- fejs u(cid:285)ytkownika wywo(cid:239)uje na zapleczu odpowiedni(cid:200) metod(cid:218). Je(cid:285)eli j(cid:200) wywo(cid:239)uje, szczegó(cid:239)y jej dzia(cid:239)ania w kontek(cid:258)cie integracji nie maj(cid:200) znaczenia, poniewa(cid:285) wiadomo, (cid:285)e wszystkie przy- padki s(cid:200) sprawdzane na poziomie jednostkowym. 92 Poleć książkęKup książkę Rozdzia(cid:225) 4. • Testy jednostkowe Rysunek 4.1. Piramida testów — testy interfejsu u(cid:285)ytkownika (IU), integracyjne i jednostkowe Testy jednostkowe w TDD Jaka jest specyfika pisania testów jednostkowych w kontek(cid:258)cie TDD? Najwa(cid:285)niejszy jest tu czas pisania testów. W tradycyjnych podej(cid:258)ciach testy jednostkowe s(cid:200) pisane po przygotowa- niu kodu rozwi(cid:200)zania, w TDD natomiast testy s(cid:200) pisane na pocz(cid:200)tku. Kolejno(cid:258)(cid:202) prac jest wi(cid:218)c odwrócona. Tradycyjnie (bez stosowania TDD) celem testów jednostkowych jest sprawdzanie poprawno(cid:258)ci ju(cid:285) istniej(cid:200)cego kodu. Zgodnie z TDD to testy jednostkowe powinny sterowa(cid:202) tworzeniem kodu i projektu. To testy powinny definiowa(cid:202) dzia(cid:239)anie mo(cid:285)liwie najmniejszych jednostek. Testy s(cid:200) wtedy mikrowymaganiami czekaj(cid:200)cymi na spe(cid:239)nienie. Testy okre(cid:258)laj(cid:200), co nale(cid:285)y zrobi(cid:202) w nast(cid:218)pnym kroku i kiedy kod jest gotowy. W zale(cid:285)no(cid:258)ci od typu stosowanych testów (czy s(cid:200) to testy jednostkowe, funkcjonalne, czy integracyjne) zakres pó(cid:283)niejszych dzia(cid:239)a(cid:241) jest inny. Gdy w TDD u(cid:285)ywane s(cid:200) testy jednostkowe, zakres prac jest najmniejszy i ogranicza si(cid:218) do metody lub, cz(cid:218)(cid:258)ciej, jej fragmentu. Ponadto nale(cid:285)y wtedy stosowa(cid:202) si(cid:218) do pewnych zasad projektowych, takich jak KISS (ang. keep it simple stupid, czyli „nie komplikuj, g(cid:239)upku”). Je(cid:258)li przygotujesz proste testy o bardzo niewielkim zakresie prac, kod pozwalaj(cid:200)cy przej(cid:258)(cid:202) te testy te(cid:285) zwykle b(cid:218)dzie prosty. Dzi(cid:218)ki wyeliminowaniu z testów zewn(cid:218)trznych zale(cid:285)no(cid:258)ci trzeba odpowiednio zaprojektowa(cid:202) w kodzie rozwi(cid:200)zania podzia(cid:239) zada(cid:241). To tylko niektóre z wielu przyk(cid:239)adów ilustruj(cid:200)cych, (cid:285)e TDD pomaga pisa(cid:202) kod wy(cid:285)szej jako(cid:258)ci. Tych samych korzy(cid:258)ci nie da si(cid:218) uzyska(cid:202), stosuj(cid:200)c tylko testy jednostkowe. Bez TDD testy jednostkowe sprawdzaj(cid:200) istniej(cid:200)cy kod i nie maj(cid:200) wp(cid:239)ywu na projekt. Tak wi(cid:218)c g(cid:239)ównym celem testów jednostkowych w tradycyjnym podej(cid:258)ciu (bez TDD) jest sprawdzanie poprawno(cid:258)ci gotowego kodu. Testy jednostkowe pisane na pocz(cid:200)tku, w modelu TDD, s(cid:239)u(cid:285)(cid:200) g(cid:239)ównie do tworzenia specyfikacji i projektu. Sprawdzanie poprawno(cid:258)ci jest tylko dodatkow(cid:200) korzy(cid:258)ci(cid:200), przy czym testy maj(cid:200) wtedy zazwyczaj wy(cid:285)sz(cid:200) jako(cid:258)(cid:202) ni(cid:285) wówczas, gdy powstaj(cid:200) dopiero po napisaniu kodu rozwi(cid:200)zania. 93 Poleć książkęKup książkę TDD. Programowanie w Javie sterowane testami TDD zmusza do przemy(cid:258)lenia wymaga(cid:241) i projektu, pisania przejrzystego i dzia(cid:239)aj(cid:200)cego kodu, tworzenia wykonywalnych wymaga(cid:241) oraz bezpiecznego i cz(cid:218)stego refaktoryzowania rozwi(cid:200)- zania. Ponadto uzyskujesz wysokie pokrycie kodu testami, co pozwala przeprowadzi(cid:202) testy regresyjne ca(cid:239)ego kodu po wprowadzeniu w nim zmian. Efektem testów jednostkowych bez TDD s(cid:200) tylko testy, i to cz(cid:218)sto o w(cid:200)tpliwej jako(cid:258)ci. Platforma TestNG JUnit i TestNG to dwie g(cid:239)ówne platformy do testowania kodu w Javie. W poprzednim roz- dziale pisa(cid:239)e(cid:258) ju(cid:285) testy za pomoc(cid:200) platformy JUnit i, miejmy nadziej(cid:218), dobrze rozumiesz jej dzia(cid:239)anie. A co z TestNG? Ta platforma powsta(cid:239)a w celu utworzenia ulepszonej wersji JUnit. I rzeczywi(cid:258)cie — zawiera pewne funkcje niedost(cid:218)pne w JUnit. W dalszych punktach znajdziesz przegl(cid:200)d ró(cid:285)nic mi(cid:218)dzy tymi dwoma platformami. Autorzy tej ksi(cid:200)(cid:285)ki staraj(cid:200) si(cid:218) nie tylko wyja(cid:258)ni(cid:202) te ró(cid:285)nice, ale te(cid:285) oceni(cid:202) ich znaczenie w kontek(cid:258)cie stosowania testów jednostkowych razem z TDD. Adnotacja @Test W platformach JUnit i TestNG adnotacja @Test jest u(cid:285)ywana do wskazywania metod uznawa- nych za test. W JUnit ka(cid:285)da taka metoda musi mie(cid:202) adnotacj(cid:218) @Test, w TestNG natomiast mo(cid:285)na umie(cid:258)ci(cid:202) t(cid:218) adnotacj(cid:218) na poziomie klasy. Ta adnotacja na poziomie klasy sprawia, (cid:285)e wszystkie metody publiczne s(cid:200) uznawane za testy, chyba (cid:285)e programista doda do wybranych metod inne modyfikatory. @Test public class DirectionSpec { public void whenGetFromShortNameNThenReturnDirectionN() { Direction direction = Direction.getFromShortName( N ); assertEquals(direction, Direction.NORTH); } public void whenGetFromShortNameWThenReturnDirectionW() { Direction direction = Direction.getFromShortName( W ); assertEquals(direction, Direction.WEST); } } W tym przyk(cid:239)adzie adnotacja @Test znajduje si(cid:218) nad klas(cid:200) DirectionSpec. Dlatego metody whenGetFromShortNameNThenReturnDirectionN i whenGetFromShortNameWThenReturnDirectionW s(cid:200) uznawane za testy. W tym samym kodzie w platformie JUnit adnotacja @Test musi si(cid:218) znaj- dowa(cid:202) przy obu metodach. 94 Poleć książkęKup książkę Rozdzia(cid:225) 4. • Testy jednostkowe Adnotacje @BeforeSuit, @BeforeTest, @BeforeGroups, @AfterGroups, @AfterTest i @AfterSuit Te adnotacje nie maj(cid:200) swoich odpowiedników w platformie JUnit. Platforma TestNG pozwala grupowa(cid:202) testy w pakiety za pomoc(cid:200) konfiguracji w formacie XML. Metody z adnotacjami @BeforeSuit i @AfterSuit s(cid:200) uruchamiane przed testami z pakietu lub po ca(cid:239)ym pakiecie. Metody z adnotacjami @BeforeTest i @AfterTest s(cid:200) wykonywane przed ka(cid:285)d(cid:200) metod(cid:200) testow(cid:200) z klasy albo po ka(cid:285)dej takiej metodzie. Testy w platformie TestNG mo(cid:285)na te(cid:285) (cid:239)(cid:200)czy(cid:202) w grupy. Adnotacje @BeforeGroup i @AfterGroup umo(cid:285)liwiaj(cid:200) uruchamianie metod przed pierwszym testem z grupy i po wykonaniu wszystkich testów z grupy. Cho(cid:202) te adnotacje mog(cid:200) by(cid:202) bardzo u(cid:285)yteczne, je(cid:258)li testy s(cid:200) pisane po kodzie rozwi(cid:200)zania, w kontek(cid:258)cie TDD ich przydatno(cid:258)(cid:202) jest umiarkowana. Inaczej ni(cid:285) w tradycyjnych testach, które cz(cid:218)sto planuje si(cid:218) i pisze w ramach odr(cid:218)bnego projektu, w TDD nale(cid:285)y dodawa(cid:202) za ka(cid:285)dym razem jeden prosty test. Jeszcze wa(cid:285)niejsze jest to, (cid:285)e testy maj(cid:200) dzia(cid:239)a(cid:202) szybko, dla- tego nie trzeba (cid:239)(cid:200)czy(cid:202) ich w pakiety lub grupy. Gdy testy dzia(cid:239)aj(cid:200) szybko, pomijanie których(cid:258) z nich jest marnotrawstwem. Je(cid:258)li wszystkie testy mo(cid:285)na wykona(cid:202) na przyk(cid:239)ad w mniej ni(cid:285) 15 sekund, nie ma potrzeby uruchamia(cid:202) tylko cz(cid:218)(cid:258)ci z nich. Natomiast gdy testy dzia(cid:239)aj(cid:200) powoli, cz(cid:218)sto oznacza to, (cid:285)e nie odizolowano zewn(cid:218)trznych zale(cid:285)no(cid:258)ci. Niezale(cid:285)nie od przyczyn wp(cid:239)ywaj(cid:200)cych na powolne wykonywanie testów rozwi(cid:200)zanie nie powinno polega(cid:202) na wyko- nywaniu tylko wybranych z nich, ale na naprawieniu problemu. Ponadto testy funkcjonalne i integracyjne s(cid:200) zwykle wolniejsze i wymagaj(cid:200) rozdzielenia. Warto rozdzieli(cid:202) je na przyk(cid:239)ad za pomoc(cid:200) instrukcji z pliku build.gradle, tak by dla ka(cid:285)dego typu testów u(cid:285)ywane by(cid:239)o odr(cid:218)bne zadanie. Adnotacje @BeforeClass i @AfterClass Te adnotacje dzia(cid:239)aj(cid:200) tak samo w platformach JUnit i TestNG. Metody z tymi adnotacjami s(cid:200) uruchamiane przed pierwszym testem i po ostatnim te(cid:258)cie z danej klasy. Jedyna ró(cid:285)nica pole- ga na tym, (cid:285)e w platformie TestNG metody z t(cid:200) adnotacj(cid:200) nie musz(cid:200) by(cid:202) statyczne. Jest tak, poniewa(cid:285) w obu platformach stosowane s(cid:200) odmienne podej(cid:258)cia w trakcie uruchamiania me- tod z testami. Platforma JUnit izoluje testy i uruchamia je w odr(cid:218)bnych egzemplarzach klasy z testami. Dlatego metody trzeba zdefiniowa(cid:202) jako statyczne, co pozwala wielokrotnie wyko- rzysta(cid:202) je we wszystkich przebiegach testów. Platforma TestNG wykonuje wszystkie metody testowe w kontek(cid:258)cie jednego egzemplarza klasy, metody nie musz(cid:200) by(cid:202) wi(cid:218)c statyczne. Adnotacje @BeforeMethod i @AfterMethod Adnotacje @BeforeMethod i @AfterMethod dzia(cid:239)aj(cid:200) tak jak ich odpowiedniki z platformy JUnit. Metody z tymi adnotacjami s(cid:200) uruchamiane przed ka(cid:285)d(cid:200) metod(cid:200) testow(cid:200) i po ka(cid:285)dej takiej metodzie. 95 Poleć książkęKup książkę TDD. Programowanie w Javie sterowane testami Argument w adnotacji @Test(enable = false) Platformy JUnit i TestNG umo(cid:285)liwiaj(cid:200) wy(cid:239)(cid:200)czenie testów. W platformie JUnit s(cid:239)u(cid:285)y do tego odr(cid:218)bna adnotacja @Ignore, w platformie TestNG natomiast nale(cid:285)y u(cid:285)y(cid:202) argumentu logicznego enable w adnotacji @Test. Oba te rozwi(cid:200)zania dzia(cid:239)aj(cid:200) tak samo, a ró(cid:285)nica polega tylko na zapisie. Argument w adnotacji @Test(expectedExceptions = NazwaKlasy.class) W tym punkcie platforma JUnit ma przewag(cid:218). Cho(cid:202) obie platformy umo(cid:285)liwiaj(cid:200) wskazywanie oczekiwanych wyj(cid:200)tków w ten sam sposób (przy czym w platformie JUnit s(cid:239)u(cid:285)(cid:200)cy do tego argument nosi nazw(cid:218) expected), JUnit udost(cid:218)pnia regu(cid:239)y, które pozwalaj(cid:200) w bardziej ele- gancki sposób testowa(cid:202) wyj(cid:200)tki. Z regu(cid:239) korzysta(cid:239)e(cid:258) ju(cid:285) w rozdziale 2., „Narz(cid:218)dzia, platformy i (cid:258)rodowiska”. Podsumowanie porównania platform TestNG i JUnit Mi(cid:218)dzy omawianymi platformami wyst(cid:218)puj(cid:200) te(cid:285) liczne inne ró(cid:285)nice. By zachowa(cid:202) zwi(cid:218)z(cid:239)o(cid:258)(cid:202), nie opisano ich wszystkich w tej ksi(cid:200)(cid:285)ce. Wi(cid:218)cej informacji znajdziesz w dokumentacji obu narz(cid:218)dzi. Wi(cid:218)cej informacji o platformach JUnit i TestNG znajdziesz na stronach http://junit.org/ i http://testng.org/. Platforma TestNG udost(cid:218)pnia wi(cid:218)cej funkcji i jest bardziej zaawansowana ni(cid:285) JUnit. W tym rozdziale b(cid:218)dziesz u(cid:285)ywa(cid:239) platformy TestNG, dzi(cid:218)ki czemu lepiej j(cid:200) poznasz. Zauwa(cid:285)ysz jed- nak, (cid:285)e nie s(cid:200) tu stosowane (cid:285)adne z zaawansowanych funkcji tej platformy. Wynika to z tego, (cid:285)e w TDD rzadko s(cid:200) one potrzebne w trakcie tworzenia testów jednostkowych. Testy funk- cjonalne i integracyjne dzia(cid:239)aj(cid:200) inaczej, dlatego pozwoli(cid:239)yby lepiej zademonstrowa(cid:202) przewag(cid:218) platformy TestNG. Istniej(cid:200) jednak narz(cid:218)dzia lepiej dostosowane do takich testów. Przekonasz si(cid:218) o tym w dalszych rozdzia(cid:239)ach. Której z tych platform powiniene(cid:258) u(cid:285)ywa(cid:202)? Wybór nale(cid:285)y do Ciebie. Do czasu zako(cid:241)czenia lektury tego rozdzia(cid:239)u zdob(cid:218)dziesz praktyczne umiej(cid:218)tno(cid:258)ci pos(cid:239)ugiwania si(cid:218) zarówno platform(cid:200) JUnit, jak i platform(cid:200) TestNG. 96 Poleć książkęKup książkę Rozdzia(cid:225) 4. • Testy jednostkowe Wymagania dotycz(cid:200)ce zdalnie sterowanego statku Tu wykonasz odmian(cid:218) dobrze znanego (cid:202)wiczenia Mars Rover, opublikowanego po raz pierwszy w witrynie Dallas Hack Club (http://dallashackclub.com/rover). Wyobra(cid:283) sobie, (cid:285)e gdzie(cid:258) po morzach p(cid:239)ywa statek. Poniewa(cid:285) (cid:285)yjemy w XXI wieku, maszyn(cid:200) mo(cid:285)na sterowa(cid:202) zdalnie. Zadanie polega na napisaniu programu, który pozwala sterowa(cid:202) przemieszczaniem si(cid:218) statku po morzach. Jako (cid:285)e jest to ksi(cid:200)(cid:285)ka o TDD, a tematem tego rozdzia(cid:239)u s(cid:200) testy jednostkowe, rozwiniesz aplikacj(cid:218) za pomoc(cid:200) TDD, koncentruj(cid:200)c si(cid:218) na testach jednostkowych. W poprzednim rozdziale pozna(cid:239)e(cid:258) procedur(cid:218) czerwone, zielone, refaktoryzacja w teorii, a tak(cid:285)e wypróbowa(cid:239)e(cid:258) j(cid:200) w praktyce. Tu wy- korzystasz zdobyt(cid:200) wcze(cid:258)niej wiedz(cid:218) i nauczysz si(cid:218) skutecznie stosowa(cid:202) testy jednostkowe. Skoncentrujesz si(cid:218) na rozwijanej jednostce i dowiesz si(cid:218), jak izolowa(cid:202) i pomija(cid:202) zale(cid:285)no(cid:258)ci, które mog(cid:200) by(cid:202) potrzebne w danej jednostce. Nast(cid:218)pnym celem jest uwzgl(cid:218)dnianie w ka(cid:285)dym kroku tylko jednego wymagania. Dlatego prezentowane s(cid:200) tu wy(cid:239)(cid:200)cznie wymagania wysokiego poziomu. U(cid:285)ytkownik powinien móc zdalnie sterowa(cid:202) statkiem zlokalizowanym w dowolnym miejscu (cid:258)wiata. W celu uproszczenia Ci pracy wszystkie klasy pomocnicze zosta(cid:239)y ju(cid:285) napisane i przetestowane. Dzi(cid:218)ki temu mo(cid:285)esz si(cid:218) skoncentrowa(cid:202) tylko na g(cid:239)ównym zadaniu, a (cid:202)wiczenie b(cid:218)dzie zwi(cid:218)z(cid:239)e. Pisanie kodu do zdalnego sterowania statkiem Zacznij od zaimportowania istniej(cid:200)cego repozytorium Git. Przygotowywanie projektu Rozpocznij od przygotowania projektu. 1. Otwórz (cid:258)rodowisko IntelliJ IDEA. Je(cid:258)li otwarty jest istniej(cid:200)cy projekt, wybierz opcj(cid:218) File/Close Project. Pojawi si(cid:218) ekran podobny do ekranu widocznego na rysunku 4.2. 2. Aby zaimportowa(cid:202) projekt z repozytorium Git, wybierz opcj(cid:218) Check out from Version Control/Git. Wpisz https://bitbucket.org/vfarcic/tdd-java-ch04-ship.git w polu Git Repository URL i kliknij przycisk Clone (zobacz rysunek 4.3). 97 Poleć książkęKup książkę TDD. Programowanie w Javie sterowane testami Rysunek 4.2. Pocz(cid:200)tkowy ekran (cid:258)rodowiska IntelliJ IDEA Rysunek 4.3. Importowanie projektu z repozytorium Git 3. Gdy zobaczysz pytanie o to, czy chcesz otworzy(cid:202) projekt, wybierz opcj(cid:218) Yes. Nast(cid:218)pnie zobaczysz pokazane na rysunku 4.4 okno dialogowe Import Project from Gradle. Kliknij przycisk OK. Rysunek 4.4. Otwieranie projektu 98 Poleć książkęKup książkę Rozdzia(cid:225) 4. • Testy jednostkowe 4. (cid:165)rodowisko IDEA potrzebuje czasu na pobranie wszystkich zale(cid:285)no(cid:258)ci opisanych w pliku build.gradle. Po zako(cid:241)czeniu ich wczytywania zobaczysz, (cid:285)e niektóre klasy i powi(cid:200)zane z nimi testy s(cid:200) ju(cid:285) gotowe. Przedstawia to rysunek 4.5. Rysunek 4.5. Struktura wczytanego projektu Klasy pomocnicze Wyobra(cid:283) sobie, (cid:285)e prace nad tym projektem rozpocz(cid:200)(cid:239) Twój wspó(cid:239)pracownik. Jest dobrym programist(cid:200) i praktykiem TDD. Ufasz, (cid:285)e zapewni(cid:239) dobre pokrycie kodu testami, dlatego mo- (cid:285)esz polega(cid:202) na jego pracy. Wspó(cid:239)pracownik nie zd(cid:200)(cid:285)y(cid:239) jednak uko(cid:241)czy(cid:202) aplikacji przed wy- jazdem na urlop i to Ty musisz kontynuowa(cid:202) rozwijanie programu. Gotowe s(cid:200) ju(cid:285) wszystkie klasy pomocnicze: Direction, Location, Planet i Point. Zauwa(cid:285), (cid:285)e przygotowane zosta(cid:239)y te(cid:285) odpowiednie klasy z testami. Nazwy klas z testami utworzono przez dodanie przedrostka Spec do nazw sprawdzanych klas (na przyk(cid:239)ad DirectionSpec). Ten przedrostek zastosowano po to, by podkre(cid:258)li(cid:202), (cid:285)e testy nie tylko s(cid:239)u(cid:285)(cid:200) do sprawdzania poprawno(cid:258)ci kodu, ale tak(cid:285)e pe(cid:239)ni(cid:200) funkcj(cid:218) wykonywalnej specyfikacji. Oprócz klas pomocniczych istniej(cid:200) równie(cid:285) klasy Ship (z rozwi(cid:200)zaniem) i ShipSpec (z testami u(cid:285)ywanymi jako specyfikacja). Wi(cid:218)kszo(cid:258)(cid:202) czasu po(cid:258)wi(cid:218)cisz na prac(cid:218) nad tymi dwoma klasami. W klasie ShipSpec b(cid:218)dziesz pisa(cid:239) testy, a nast(cid:218)pnie dodasz kod rozwi(cid:200)zania do klasy Ship. Kolejno(cid:258)(cid:202) prac b(cid:218)dzie wi(cid:218)c taka sama jak wcze(cid:258)niej. 99 Poleć książkęKup książkę TDD. Programowanie w Javie sterowane testami Poniewa(cid:285) wiesz ju(cid:285), (cid:285)e testy nie tylko s(cid:239)u(cid:285)(cid:200) do sprawdzania poprawno(cid:258)ci kodu, ale te(cid:285) s(cid:200) wykonywaln(cid:200) dokumentacj(cid:200), od tego miejsca u(cid:285)ywane b(cid:218)dzie okre(cid:258)lenie specyfikacja zamiast test. Za ka(cid:285)dym razem, gdy napiszesz specyfikacj(cid:218) lub odpowiadaj(cid:200)cy jej kod, uruchom polecenie gradle test w wierszu polece(cid:241) b(cid:200)d(cid:283) w przedstawionym na rysunku 4.6 oknie Gradle projects w (cid:258)rodowisku IDEA. Rysunek 4.6. Okno Gradle projects Po przygotowaniu projektu mo(cid:285)esz przej(cid:258)(cid:202) do pierwszego wymagania. Wymaganie nr 1 Trzeba okre(cid:258)li(cid:202) bie(cid:285)(cid:200)c(cid:200) lokalizacj(cid:218) statku, by móc go przemie(cid:258)ci(cid:202). Ponadto trzeba wiedzie(cid:202), w któr(cid:200) stron(cid:218) statek jest skierowany — na pó(cid:239)noc, na po(cid:239)udnie, na wschód czy na zachód. Tego w(cid:239)a(cid:258)nie dotyczy pierwsze wymaganie. Okre(cid:258)lone s(cid:200) punkt pocz(cid:200)tkowy (x, y) statku oraz jego kierunek (N — ang. north, czyli pó(cid:239)noc, S — ang. south, czyli po(cid:239)udnie, E — ang. east, czyli wschód, lub W — ang. west, czyli zachód). Zanim zaczniesz pracowa(cid:202) nad wymaganiem, zapoznaj si(cid:218) z dost(cid:218)pnymi klasami pomocniczymi. Klasa Point przechowuje wspó(cid:239)rz(cid:218)dne x i y. Oto konstruktor tej klasy: public Point(int x, int y) { this.x = x; this.y = y; } 100 Poleć książkęKup książkę Dost(cid:218)pna jest te(cid:285) klasa Direction enum z pokazanymi poni(cid:285)ej warto(cid:258)ciami: Rozdzia(cid:225) 4. • Testy jednostkowe public enum Direction { NORTH(0, N ), EAST(1, E ), SOUTH(2, S ), WEST(3, W ), NONE(4, X ); } Istnieje równie(cid:285) klasa Location, która wymaga przekazania obiektów obu wcze(cid:258)niej pokazanych klas jako argumentów konstruktora. public Location(Point point, Direction direction) { this.point = point; this.direction = direction; } Dzi(cid:218)ki tym klasom nie powiniene(cid:258) mie(cid:202) wi(cid:218)kszych problemów z napisaniem testu dla pierw- szego wymagania. Proces ten powinien wygl(cid:200)da(cid:202) tak samo jak w poprzednim rozdziale. Spróbuj samodzielnie napisa(cid:202) specyfikacje. Gdy je uko(cid:241)czysz, porównaj swój kod ze spe- cyfikacj(cid:200) z tej ksi(cid:200)(cid:285)ki. To samo zrób w trakcie pracy nad kodem rozwi(cid:200)zania powi(cid:200)zanym ze specyfikacj(cid:200). Spróbuj napisa(cid:202) go samodzielnie, a nast(cid:218)pnie porównaj go z proponowanym rozwi(cid:200)zaniem z tej ksi(cid:200)(cid:285)ki. Specyfikacja Oto mo(cid:285)liwa specyfikacja dla pierwszego wymagania: @Test public class ShipSpec { public void whenInstantiatedThenLocationIsSet() { Location location = new Location( new Point(21, 13), Direction.NORTH); Ship ship = new Ship(location); assertEquals(ship.getLocation(), location); } } To by(cid:239)o (cid:239)atwe. Wystarczy sprawdzi(cid:202), czy obiekt typu Location przekazany do konstruktora obiektu typu Ship jest zachowywany i czy mo(cid:285)na uzyska(cid:202) dost(cid:218)p do lokalizacji za pomoc(cid:200) gettera location. Adnotacja @Test Gdy w platformie TestNG adnotacja @Test jest ustawiona na poziomie klasy, nie trzeba okre(cid:258)la(cid:202), które metody maj(cid:200) pe(cid:239)ni(cid:202) funkcj(cid:218) testów. Wtedy wszystkie publiczne metody s(cid:200) uznawane za testy z platformy TestNG. 101 Poleć książkęKup książkę TDD. Programowanie w Javie sterowane testami Kod rozwi(cid:200)zania Kod rozwi(cid:200)zania powi(cid:200)zany ze specyfikacj(cid:200) jest stosunkowo (cid:239)atwy do napisania. Wystarczy przypisa(cid:202) argument z konstruktora do zmiennej location. public class Ship { private final Location location; public Location getLocation() { return location; } public Ship(Location location) { this.location = location; } } Kompletny kod (cid:283)ród(cid:239)owy znajdziesz w odga(cid:239)(cid:218)zieniu req1-location w repozytorium tdd-java-ch04-ship dost(cid:218)pnym na stronie https://bitbucket.org/vfarcic/tdd-java-ch04-ship/ branch/req01-location. Refaktoryzacja Wiesz, (cid:285)e obiekt typu Ship trzeba b(cid:218)dzie utworzy(cid:202) dla ka(cid:285)dej specyfikacji. Dlatego mo(cid:285)na zre- faktoryzowa(cid:202) klas(cid:218) specyfikacji i doda(cid:202) w niej adnotacj(cid:218) @BeforeMethod. Oto nowy kod tej klasy: @Test public class ShipSpec { private Ship ship; private Location location; @BeforeMethod public void beforeTest() { Location location = new Location( new Point(21, 13), Direction.NORTH); ship = new Ship(location); } public void whenInstantiatedThenLocationIsSet() { // Location location = new Location( // new Point(21, 13), Direction.NORTH); // Ship ship = new Ship(location); assertEquals(ship.getLocation(), location); } } 102 Poleć książkęKup książkę Rozdzia(cid:225) 4. • Testy jednostkowe Nie dodano tu (cid:285)adnych nowych operacji. Wystarczy(cid:239)o przenie(cid:258)(cid:202) fragment kodu do adnotacji @BeforeMethod, by unikn(cid:200)(cid:202) powtórze(cid:241), które powsta(cid:239)yby w trakcie pisania dalszych specyfikacji. Teraz przy ka(cid:285)dym uruchomieniu testu utworzony zostanie obiekt typu Ship z argumentem location. Wymaganie nr 2 Gdy wiesz ju(cid:285), gdzie statek si(cid:218) znajduje, spróbuj go przesun(cid:200)(cid:202). Zacznij od mo(cid:285)liwo(cid:258)ci prze- mieszczania go do przodu i do ty(cid:239)u. Dodaj obs(cid:239)ug(cid:218) polece(cid:241) przesuwaj(cid:200)cych statek naprzód (n) i wstecz (w). Klasa pomocnicza Location udost(cid:218)pnia ju(cid:285) metody forward i backward obs(cid:239)uguj(cid:200)ce takie polecenia. public boolean forward() { ... } Specyfikacja Co si(cid:218) powinno sta(cid:202), gdy statek jest skierowany na pó(cid:239)noc i u(cid:285)ytkownik przesunie go do przodu? Warto(cid:258)(cid:202) wspó(cid:239)rz(cid:218)dnej y powinna si(cid:218) zmniejszy(cid:202). Inny przyk(cid:239)ad to przesuni(cid:218)cie do przodu statku skierowanego na wschód; w takiej sytuacji nale(cid:285)y zwi(cid:218)kszy(cid:202) warto(cid:258)(cid:202) wspó(cid:239)rz(cid:218)dnej x. Pierwsz(cid:200) reakcj(cid:200) mo(cid:285)e by(cid:202) napisanie specyfikacji podobnych do dwóch poni(cid:285)szych: public void givenNorthWhenMoveForwardThenYDecreases() { ship.moveForward(); assertEquals(ship.getLocation().getPoint().getY(), 12); } public void givenEastWhenMoveForwardThenXIncreases() { ship.getLocation().setDirection(Direction.EAST); ship.moveForward(); assertEquals(ship.getLocation().getPoint().getX(), 22); } W tym podej(cid:258)ciu trzeba utworzy(cid:202) jeszcze przynajmniej dwie specyfikacje dotycz(cid:200)ce sytuacji, w których statek jest skierowany na po(cid:239)udnie i na zachód. Jednak nie tak nale(cid:285)y pisa(cid:202) testy jednostkowe. Wi(cid:218)kszo(cid:258)(cid:202) osób zaczynaj(cid:200)cych stosowanie takich testów wpada w pu(cid:239)apk(cid:218) okre(cid:258)lania wyników ko(cid:241)cowych wymagaj(cid:200)cych znajomo(cid:258)ci wewn(cid:218)trznych mechanizmów metod, klas i bibliotek u(cid:285)ywanych przez sprawdzan(cid:200) metod(cid:218). To podej(cid:258)cie prowadzi do problemów na wielu poziomach. 103 Poleć książkęKup książkę TDD. Programowanie w Javie sterowane testami Gdy w sprawdzanej jednostce korzystasz z kodu zewn(cid:218)trznego, powiniene(cid:258) pami(cid:218)ta(cid:202) o tym, (cid:285)e — przynajmniej w tym przyk(cid:239)adzie — zewn(cid:218)trzny kod jest ju(cid:285) przetestowany. Po ka(cid:285)dej zmianie wykonywane s(cid:200) wszystkie testy, dlatego wiadomo, (cid:285)e kod zewn(cid:218)trzny dzia(cid:239)a. Zawsze po wprowadzeniu zmian w kodzie rozwi(cid:200)zania uruchamiaj wszystkie testy To gwarantuje, (cid:285)e nie pojawi(cid:200) si(cid:218) nieoczekiwane efekty uboczne spowodowane zmianami w kodzie. Za ka(cid:285)dym razem, gdy zmodyfikujesz jak(cid:200)(cid:258) cz(cid:218)(cid:258)(cid:202) kodu rozwi(cid:200)zania, przeprowad(cid:283) wszystkie testy. W ideal- nych warunkach testy powinny dzia(cid:239)a(cid:202) szybko i by(cid:202) wykonywane lokalnie przez programist(cid:218). Po prze- s(cid:239)aniu kodu do systemu kontroli wersji wszystkie testy nale(cid:285)y przeprowadzi(cid:202) jeszcze raz, by si(cid:218) upewni(cid:202), (cid:285)e nie wyst(cid:200)pi(cid:239)y problemy wynikaj(cid:200)ce ze scalania kodu. Jest to wa(cid:285)ne zw(cid:239)aszcza wtedy, gdy nad kodem pracuje kilka osób. Do pobrania kodu z repozytorium, skompilowania rozwi(cid:200)zania i wykonania testów mo(cid:285)na wykorzysta(cid:202) narz(cid:218)dzia do obs(cid:239)ugi ci(cid:200)g(cid:239)ej integracji, takie jak Jenkins, Hudson, Travind, Bamboo lub Go-CD. Inny problem z opisanym podej(cid:258)ciem polega na tym, (cid:285)e je(cid:258)li w zewn(cid:218)trznym kodzie pojawi(cid:200) si(cid:218) zmiany, trzeba b(cid:218)dzie zmodyfikowa(cid:202) wiele specyfikacji. Najlepiej jest, gdy zmiany s(cid:200) niezb(cid:218)dne tylko w specyfikacjach bezpo(cid:258)rednio powi(cid:200)zanych z modyfikowan(cid:200) jednostk(cid:200). Wyszukiwanie w in- nych miejscach wywo(cid:239)a(cid:241) danej jednostki bywa bardzo czasoch(cid:239)onne i grozi powstawaniem b(cid:239)(cid:218)dów. Poni(cid:285)ej pokazano znacznie (cid:239)atwiejszy, szybszy i lepszy sposób na napisanie specyfikacji dla omawianego wymagania. public void whenMoveForwardThenForward() { Location expected = location.copy(); expected.forward(); ship.moveForward(); assertEquals(ship.getLocation(), expected); } Poniewa(cid:285) klasa Location ma ju(cid:285) metod(cid:218) forward, wystarczy si(cid:218) upewni(cid:202), (cid:285)e metoda ta zosta- nie poprawnie wywo(cid:239)ana. Tu kod tworzy nowy obiekt expected typu Location, wywo(cid:239)uje jego metod(cid:218) forward i porównuje lokalizacj(cid:218) obiekt expected z lokalizacj(cid:200) statku po wywo(cid:239)aniu jego metody moveForward. Zauwa(cid:285), (cid:285)e specyfikacje s(cid:239)u(cid:285)(cid:200) nie tylko do sprawdzania poprawno(cid:258)ci kodu. S(cid:200) równie(cid:285) u(cid:285)y- wane jako wykonywalna dokumentacja i, co najwa(cid:285)niejsze, wspomagaj(cid:200) my(cid:258)lenie oraz pro- jektowanie. Druga wersja specyfikacji bardziej precyzyjnie okre(cid:258)la jej przeznaczenie. W klasie Ship nale(cid:285)y doda(cid:202) metod(cid:218) moveForward i wywo(cid:239)a(cid:202) w niej instrukcj(cid:218) location.forward. Kod rozwi(cid:200)zania Po przygotowaniu tak krótkiej i jasno zdefiniowanej specyfikacji napisanie kodu, który po- zwala j(cid:200) spe(cid:239)ni(cid:202), powinno by(cid:202) (cid:239)atwe. public boolean moveForward() { return location.forward(); } 104 Poleć książkęKup książkę Rozdzia(cid:225) 4. • Testy jednostkowe Specyfikacja Po utworzeniu specyfikacji dotycz(cid:200)cej ruchu do przodu i napisaniu odpowiadaj(cid:200)cego jej kodu rozwi(cid:200)zania pora zaj(cid:200)(cid:202) si(cid:218) ruchem wstecz. Specyfikacja wygl(cid:200)da tu prawie identycznie. public void whenMoveBackwardThenBackward() { Location expected = location.copy(); expected.backward(); ship.moveBackward(); assertEquals(ship.getLocation(), expected); } Kod rozwi(cid:200)zania Kod rozwi(cid:200)zania zwi(cid:200)zany z ruchem wstecz jest, podobnie jak kod specyfikacji, (cid:239)atwy do napisania. public boolean moveBackward() { return location.backward(); } Kompletny kod (cid:283)ród(cid:239)owy dotycz(cid:200)cy tego wymagania znajdziesz w odga(cid:239)(cid:218)zieniu req02-forward- (cid:180)backward w repozytorium tdd-java-ch04-ship dost(cid:218)pnym na stronie https://bitbucket.org/ vfarcic/tdd-java-ch04-ship/branch/req02-forward-backward. Wymaganie nr 3 Przemieszczanie statku tylko do przodu i do ty(cid:239)u nie wystarczy. Potrzebna jest te(cid:285) mo(cid:285)liwo(cid:258)(cid:202) sterowania statkiem i robienia zwrotów w lewo oraz w prawo. Dodaj polecenia powoduj(cid:200)ce obrót statku w lewo (l) i prawo (p). Po dodaniu kodu rozwi(cid:200)zania dla poprzedniego wymagania nowe zadanie nie powinno sprawi(cid:202) Ci (cid:285)adnych trudno(cid:258)ci, poniewa(cid:285) mo(cid:285)na w nim wykorzysta(cid:202) t(cid:218) sam(cid:200) logik(cid:218). Klasa pomocnicza Location zawiera ju(cid:285) metody turnLeft i turnRight, które wykonuj(cid:200) okre(cid:258)lone w wymaganiu operacje. Teraz wystarczy zintegrowa(cid:202) te metody z klas(cid:200) Ship. Specyfikacja Oto specyfikacja zwrotu w lewo oparta na tych samych pomys(cid:239)ach, które wykorzystano wcze(cid:258)niej: public void whenTurnLeftThenLeft() { Location expected = location.copy(); expected.turnLeft(); ship.turnLeft(); assertEquals(ship.getLocation(), expected); } 105 Poleć książkęKup książkę TDD. Programowanie w Javie sterowane testami Kod rozwi(cid:200)zania Napisanie kodu dla nowej specyfikacji prawdopodobnie nie sprawi(cid:239)o Ci trudno(cid:258)ci. public void turnLeft() { location.turnLeft(); } Specyfikacja Specyfikacja zwrotu w prawo powinna wygl(cid:200)da(cid:202) niemal identycznie jak specyfikacja zwrotu w lewo. public void whenTurnRightThenRight() { Location expected = location.copy(); expected.turnRight(); ship.turnRight(); assertEquals(ship.getLocation(), expected); } Kod rozwi(cid:200)zania Teraz zako(cid:241)cz prace nad omawianym wymaganiem i dodaj kod rozwi(cid:200)zania odpowiadaj(cid:200)cy specyfikacji zwrotu w prawo. public void turnRight() { location.turnRight(); } Kompletny kod (cid:283)ród(cid:239)owy dotycz(cid:200)cy tego wymagania znajdziesz w odga(cid:239)(cid:218)zieniu req3-left-right w repozytorium tdd-java-ch04-ship. Kod ten jest dost(cid:218)pny na stronie https://bitbucket.org/ vfarcic/tdd-java-ch04-ship/branch/req03-left-right. Wymaganie nr 4 Wszystkie dotychczasowe zadania by(cid:239)y stosunkowo (cid:239)atwe, poniewa(cid:285) potrzebne funkcje by(cid:239)y dost(cid:218)pne w klasach pomocniczych. Dzi(cid:218)ki temu dowiedzia(cid:239)e(cid:258) si(cid:218), (cid:285)e trzeba si(cid:218) skupi(cid:202) na rozwijanej jednostce, nie nale(cid:285)y natomiast próbowa(cid:202) testowa(cid:202) efektów ko(cid:241)cowych. W ten sposób mo(cid:285)esz zbudowa(cid:202) zaufanie. Powiniene(cid:258) ufa(cid:202), (cid:285)e opracowany przez innych kod (klasy pomocnicze) jest prawid(cid:239)owy. Pocz(cid:200)wszy od wymagania nr 4, b(cid:218)dziesz musia(cid:239) zacz(cid:200)(cid:202) wierzy(cid:202) w poprawno(cid:258)(cid:202) kodu napisanego samodzielnie. Prace b(cid:218)d(cid:200) si(cid:218) toczy(cid:239)y w takim samym modelu jak wcze(cid:258)niej. Napiszesz specyfikacj(cid:218), uruchomisz testy, wykryjesz niepowodzenie, napiszesz kod rozwi(cid:200)zania, wykonasz testy, stwierdzisz, (cid:285)e ko(cid:241)cz(cid:200) si(cid:218) sukcesem, a w ostatnim kroku przeprowadzisz refaktoryzacj(cid:218) (je(cid:258)li uznasz, (cid:285)e kod mo(cid:285)na poprawi(cid:202)). Staraj si(cid:218) my(cid:258)le(cid:202) o tym, jak przetestowa(cid:202) jednostk(cid:218) (metod(cid:218)) bez zag(cid:239)(cid:218)biania si(cid:218) w dzia(cid:239)anie metod i klas wywo(cid:239)ywa- nych przez t(cid:218) jednostk(cid:218). 106 Poleć książkęKup książkę Rozdzia(cid:225) 4. • Testy jednostkowe Po dodaniu obs(cid:239)ugi poszczególnych instrukcji (naprzód, w ty(cid:239), w lewo i w prawo) pora po(cid:239)(cid:200)czy(cid:202) ca(cid:239)e rozwi(cid:200)zanie w jedn(cid:200) ca(cid:239)o(cid:258)(cid:202). Nale(cid:285)y utworzy(cid:202) metod(cid:218), która pozwoli przekaza(cid:202) dowoln(cid:200) sekwencj(cid:218) polece(cid:241) w jednym (cid:239)a(cid:241)cuchu znaków. Ka(cid:285)de polecenie to litera: n oznacza „naprzód”, w to „wstecz”, l to „lewo”, a p to „prawo”. Statek przyjmuje (cid:239)a(cid:241)cuch znaków z poleceniami (literami nwlp, oznaczaj(cid:200)cymi naprzód, wstecz, lewo i prawo). Specyfikacja Zacznij od polecenia z argumentem obejmuj(cid:200)cym tylko liter(cid:218) n (naprzód). public void whenReceiveCommandsFThenForward() { Location expected = location.copy(); expected.forward(); ship.receiveCommands( f ); assertEquals(ship.getLocation(), expected); } Ta specyfikacja wygl(cid:200)da niemal tak samo jak specyfikacja whenMoveForwardThenForward, jednak tym razem wywo(cid:239)ywana jest metoda ship.receiveCommands( f ). Kod rozwi(cid:200)zania Wcze(cid:258)niej napisano ju(cid:285) o tym, jak wa(cid:285)ne jest pisanie mo(cid:285)liwie najprostszego kodu zgodnego ze specyfikacj(cid:200). Pisz jak najprostszy kod, który przejdzie testy. Dzi(cid:218)ki temu uzyskasz bardziej uporz(cid:200)dkowany i przejrzysty projekt oraz unikniesz dodawania zb(cid:218)dnych funkcji To podej(cid:258)cie oparte jest na za(cid:239)o(cid:285)eniu, (cid:285)e im prostszy jest kod rozwi(cid:200)zania, tym (cid:239)atwiejsza b(cid:218)dzie jego konserwacja. Jest to zgodne z regu(cid:239)(cid:200) KISS. Mówi ona, (cid:285)e wi(cid:218)kszo(cid:258)(cid:202) systemów pracuje najlepiej, je(cid:258)li systemy te s(cid:200) proste, a nie skomplikowane. Dlatego prostota powinna by(cid:202) podstawowym celem w trak- cie tworzenia projektu. Nale(cid:285)y natomiast unika(cid:202) zb(cid:218)dnych komplikacji. Jest to dobry moment na zastosowanie wspomnianej regu(cid:239)y. Mo(cid:285)liwe, (cid:285)e chcesz napisa(cid:202) fragment kodu podobny do poni(cid:285)szego: public void receiveCommands(String commands) { if (commands.charAt(0) == f ) { moveForward(); } } 107 Poleć książkęKup książkę TDD. Programowanie w Javie sterowane testami Ten przyk(cid:239)adowy kod sprawdza, czy pierwsza litera to f. Je(cid:258)li tak jest, kod wywo(cid:239)uje metod(cid:218) moveForward. Istnieje te(cid:285) wiele innych mo(cid:285)liwych wersji tego kodu. Je(cid:285)eli jednak stosujesz si(cid:218) do regu(cid:239)y zach(cid:218)caj(cid:200)cej do zachowania prostoty, powiniene(cid:258) napisa(cid:202) lepsze rozwi(cid:200)zanie: public void receiveCommands(String command) { moveForward(); } Jest to najprostszy i najkrótszy kod, który pozwala przej(cid:258)(cid:202) test. Pó(cid:283)niej mo(cid:285)esz uzyska(cid:202) co(cid:258) bardziej podobnego do pierwszej wersji kodu. Mo(cid:285)liwe, (cid:285)e zastosujesz p(cid:218)tl(cid:218) lub wymy(cid:258)lisz inne rozwi(cid:200)zanie, gdy zadanie stanie si(cid:218) bardziej skomplikowane. Jednak na razie nale(cid:285)y si(cid:218) skoncentrowa(cid:202) na jednej specyfikacji i na tworzeniu prostego kodu. Postaraj si(cid:218) zachowa(cid:202) ja- sno(cid:258)(cid:202) umys(cid:239)u, skupiaj(cid:200)c si(cid:218) tylko na wykonywanym zadaniu. W celu zachowania zwi(cid:218)z(cid:239)o(cid:258)ci pozosta(cid:239)e specyfikacje i rozwi(cid:200)zania (dla liter w, l i p) pomini(cid:218)to. Potrzebny kod powiniene(cid:258) napisa(cid:202) samodzielnie. Nast(cid:218)pnie przejd(cid:283) do ostatniej specyfikacji dla omawianego wymagania. Specyfikacja Teraz gdy kod potrafi ju(cid:285) przetwarza(cid:202) pojedyncze polecenia (niezale(cid:285)nie od tego, jaka jest podana instrukcja), mo(cid:285)na doda(cid:202) mechanizm przesy(cid:239)ania (cid:239)a(cid:241)cuchów polece(cid:241). Oto specyfikacja tego zadania: public void whenReceiveCommandsThenAllAreExecuted() { Location expected = location.copy(); expected.turnRight(); expected.forward(); expected.turnLeft(); expected.backward(); ship.receiveCommands( pnlw ); assertEquals(ship.getLocation(), expected); } Ta specyfikacja jest nieco d(cid:239)u(cid:285)sza od poprzednich, ale nie jest skomplikowana. Kod przeka- zuje polecenia pnlw (czyli w prawo, naprzód, w lewo, wstecz) i oczekuje, (cid:285)e lokalizacja odpo- wiednio si(cid:218) zmieni. Tak jak wcze(cid:258)niej, kod nie sprawdza wyniku ko(cid:241)cowego (czyli nie okre(cid:258)la, czy zmieni(cid:239)y si(cid:218) wspó(cid:239)rz(cid:218)dne), a jedynie bada, czy u(cid:285)ywane s(cid:200) prawid(cid:239)owe wywo(cid:239)ania metod pomocniczych. Kod rozwi(cid:200)zania Oto efekt ko(cid:241)cowy: public void receiveCommands(String commands) { for (char command : commands.toCharArray()) { switch(command) { case n : moveForward(); 108 Poleć książkęKup książkę Rozdzia(cid:225) 4. • Testy jednostkowe break; case w : moveBackward(); break; case l : turnLeft(); break; case p : turnRight(); break; } } } Je(cid:258)li próbowa(cid:239)e(cid:258) samodzielnie pisa(cid:202) specyfikacje i kod rozwi(cid:200)zania oraz stara(cid:239)e(cid:258) si(cid:218) zachowa(cid:202) przy tym prostot(cid:218), w drodze do ostatecznego rozwi(cid:200)zania prawdopodobnie kilkakrotnie mu- sia(cid:239)e(cid:258) przeprowadzi(cid:202) refaktoryzacj(cid:218). Prostota jest niezwykle istotna, a refaktoryzacja cz(cid:218)sto jest korzystn(cid:200) konieczno(cid:258)ci(cid:200). W trakcie refaktoryzacji pami(cid:218)taj, (cid:285)e kod zawsze musi by(cid:202) zgodny ze wszystkimi specyfikacjami. Przeprowadzaj refaktoryzacj(cid:218) tylko wtedy, gdy wszystkie testy ko(cid:241)cz(cid:200) si(cid:218) powodzeniem Korzy(cid:258)(cid:202) z tego jest taka, (cid:285)e refaktoryzacj(cid:218) mo(cid:285)na wtedy przeprowadzi(cid:202) bezpiecznie. Je(cid:258)li ca(cid:239)y kod rozwi(cid:200)zania, który mo(cid:285)e zosta(cid:202) zmodyfikowany, jest pokryty testami, a wszystkie testy ko(cid:241)cz(cid:200) si(cid:218) powodzeniem, refaktoryzacja jest stosunkowo bezpieczna. W wi(cid:218)kszo(cid:258)ci sytuacji refaktoryza- cja nie wymaga dodawania nowych testów — wystarcz(cid:200) drobne zmiany w istniej(cid:200)cych testach. Gdy przeprowadzasz refaktoryzacj(cid:218), wszystkie testy powinny si(cid:218) ko(cid:241)czy(cid:202) powodzeniem zarówno przed zmo- dyfikowaniem kodu, jak i po jego zmianie. Kompletny kod (cid:283)ród(cid:239)owy dotycz(cid:200)cy tego wymagania znajdziesz w odga(cid:239)(cid:218)zieniu req04-commands w repozytorium tdd-java-ch04-ship. Kod ten jest dost(cid:218)pny na stronie https://bitbucket.org/ vfarcic/tdd-java-ch04-ship/branch/req04-commands. Wymaganie nr 5 Ziemia, podobnie jak inne planety, jest kul(cid:200). Gdy Ziemi(cid:218) przedstawia si(cid:218) na mapie, po dotar- ciu do jednego kra(cid:241)ca nale(cid:285)y przeskoczy(cid:202) do drugiego. Na przyk(cid:239)ad je(cid:258)li kierujesz si(cid:218) na wschód i docierasz do najdalszego punktu na Pacyfiku, powiniene(cid:258) przeskoczy(cid:202) do zachod- niej cz(cid:218)(cid:258)ci mapy i kontynuowa(cid:202) przemieszczanie si(cid:218) w kierunku Ameryki. Ponadto by upro- (cid:258)ci(cid:202) poruszanie si(cid:218), mo(cid:285)na zdefiniowa(cid:202) map(cid:218) jako siatk(cid:218). Szeroko(cid:258)(cid:202) i wysoko(cid:258)(cid:202) na siatce nale(cid:285)y wtedy przedstawi(cid:202) za pomoc(cid:200) osi X i Y. Tak wi(cid:218)c siatka b(cid:218)dzie mia(cid:239)a maksymaln(cid:200) szeroko(cid:258)(cid:202) (X) i wysoko(cid:258)(cid:202) (Y). Dodaj obs(cid:239)ug(cid:218) przeskakiwania od jednej kraw(cid:218)dzi siatki do innej. 109 Poleć książkęKup książkę TDD. Programowanie w Javie sterowane testami Specyfikacja Pierwsz(cid:200) rzecz(cid:200), jak(cid:200) trzeba zrobi(cid:202), jest przekazanie do konstruktora klasy Ship obiektu typu Planet z maksymalnymi wspó(cid:239)rz(cid:218)dnymi osi X i Y. Na szcz(cid:218)(cid:258)cie Planet to jedna z ju(cid:285) gotowych (i przetestowanych) klas pomocniczych. Teraz wystarczy utworzy(cid:202) obiekt tej klasy i przekaza(cid:202) go do konstruktora klasy Ship. public void whenInstantiatedThenPlanetIsStored() { Point max = new Point(50, 50); Planet planet = new Planet(max); ship = new Ship(location, planet); assertEquals(ship.getPlanet(), planet); } W tym kodzie zdefiniowano wymiary planety na 50 × 50 jednostek i przekazano je do obiektu klasy Planet. Nast(cid:218)pnie ten obiekt przekazano do konstruktora klasy Ship. Mo(cid:285)e zauwa(cid:285)y(cid:239)e(cid:258), (cid:285)e konstruktor b(cid:218)dzie wymaga(cid:239) teraz dodatkowego argumentu. W obecnej postaci kodu kon- struktor przyjmuje tylko obiekt typu Location. Aby napisa(cid:202) kod dla nowej specyfikacji, trzeba sprawi(cid:202), by konstruktor pobiera(cid:239) tak(cid:285)e obiekt typu Planet. Jak napiszesz rozwi(cid:200)zanie dla nowej specyfikacji, nie naruszaj(cid:200)c przy tym (cid:285)adnych istniej(cid:200)cych specyfikacji? Kod rozwi(cid:200)zania Zastosuj podej(cid:258)cie „od szczegó(cid:239)u do ogó(cid:239)u”. Zgodnie z asercj(cid:200) dost(cid:218)pny powinien by(cid:202) getter dla obiektu planet. private Planet planet; public Planet getPlanet() { return planet; } Konstruktor powinien przyjmowa(cid:202) obiekt typu Planet jako drugi argument i przypisywa(cid:202) go do wcze(cid:258)niej dodanej zmiennej planet. Pierwszym pomys(cid:239)em mo(cid:285)e by(cid:202) dodanie nowego ar- gumentu do istniej(cid:200)cego konstruktora, to jednak prowadzi do naruszenia wielu istniej(cid:200)cych specyfikacji, u(cid:285)ywaj(cid:200)cych konstruktora jednoargumentowego. Pozostaje wi(cid:218)c tylko jedna mo(cid:285)- liwo(cid:258)(cid:202) — napisa(cid:202) drugi konstruktor. public Ship(Location location) { this.location = location; } public Ship(Location location, Planet planet) { this.location = location; this.planet = planet; } Uruch
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

TDD. Programowanie w Javie sterowane testami
Autor:
,

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: