Darmowy fragment publikacji:
Java.
Praktyczne narzêdzia
Autor: John Ferguson Smart
T³umaczenie: Miko³aj Szczepaniak
ISBN: 978-83-246-1932-0
Tytu³ orygina³u: Java Power Tools
Format: 168x237, stron: 888
Poznaj narzêdzia, które oka¿¹ siê niezbêdne!
• Jak zapewniæ wysok¹ jakoœæ tworzonego rozwi¹zania?
• Jak wprowadziæ proces ci¹g³ej integracji?
• Jak testowaæ kod?
Mo¿liwoœci jêzyka Java znaj¹ ju¿ chyba wszyscy. Dlatego warto jedynie wspomnieæ
o tym, ¿e oprócz podstawowych narzêdzi do tworzenia oprogramowania w tym jêzyku,
które zna ka¿dy programista, istnieje wiele innych — przydatnych i u¿ytecznych
— aplikacji. Potrafi¹ one w niezwykle skuteczny sposób przyœpieszyæ oraz u³atwiæ
programowanie w jêzyku Java i sprawiæ, ¿e bêdzie to zajêcie jeszcze przyjemniejsze.
W ¿adnej innej ksi¹¿ce nie znajdziesz tak szczegó³owego omówienia tych narzêdzi.
Zatem jeœli wykorzystujesz jêzyk Java na co dzieñ, musisz j¹ mieæ!
Dziêki tej ksi¹¿ce poznasz 33 praktyczne narzêdzia, które u³atwi¹ Twoj¹ pracê
— narzêdzia, które zwiêksz¹ niezawodnoœæ Twojego kodu, poprawi¹ wydajnoœæ
oraz zapewni¹ bezpieczeñstwo Twoim plikom Ÿród³owym. Autor ksi¹¿ki omawia kilka
grup narzêdzi, a wœród nich aplikacje takie, jak Maven, Subversion, JUnit czy te¿
Hudson. Dziêki ksi¹¿ce „Java. Praktyczne narzêdzia” dowiesz siê, jak bardzo na jakoœæ
Twojego rozwi¹zania mo¿e wp³yn¹æ proces ci¹g³ej integracji oraz jak wa¿ne s¹ testy
jednostkowe czy integracyjne. Ponadto autor ksi¹¿ki omawia 29 innych narzêdzi,
które zwiêkszaj¹ komfort pracy. Otwórz spis treœci i spójrz, jak cenne informacje s¹
zawarte w tej ksi¹¿ce!
• Wykorzystanie narzêdzi kompiluj¹cych (Ant, Maven2)
• Zastosowanie systemów kontroli wersji (CVS, Subversion)
• Sposoby oceny jakoœci kodu (CheckStyle, PMD, FindBugs, Jupiter)
• Tworzenie wysokiej jakoœci dokumentacji
• Przygotowanie testów jednostkowych (JUnit, TestNG)
• Przeprowadzanie testów integracyjnych
• Systemy raportowania i œledzenia b³êdów (Bugzilla, Trac)
• Narzêdzia pozwalaj¹ce na wprowadzenie procesu ci¹g³ej integracji
(Continuum, Hudson)
• Sposoby przeprowadzania testów obci¹¿eniowych
• Profilowanie i monitorowanie aplikacji za pomoc¹ narzêdzi dostêpnych
w pakiecie JDK oraz Eclipse
Zobacz, jak ³atwo mo¿na wykonaæ skomplikowane zadania!
Spis treļci
Sĥowo wstýpne ........................................................................................................................17
Przedmowa ............................................................................................................................. 19
Wprowadzenie .......................................................................................................................33
I Narzýdzia kompilujéce ...........................................................................37
1. Przygotowywanie projektu z wykorzystaniem Anta ................................................ 41
41
41
44
51
53
57
75
77
81
1.1. Rola narzödzia Ant w procesie kompilacji
1.2. Instalacja Anta
1.3. Päynne wprowadzenie w Ĉwiat Anta
1.4. Kompilowanie kodu Javy za pomocñ Anta
1.5. Dostosowywanie skryptów kompilacji za pomocñ wäaĈciwoĈci
1.6. Przeprowadzanie testów jednostkowych za pomocñ Anta
1.7. Generowanie dokumentacji za pomocñ narzödzia Javadoc
1.8. Pakowanie gotowej aplikacji
1.9. WdraĔanie aplikacji
1.10.Automatyczne przygotowywanie Ĉrodowiska dla uruchamianych
skryptów kompilacji
1.11. Stosowanie zaleĔnoĈci narzödzia Maven w Ancie wraz z zadaniami Mavena
1.12. Stosowanie Anta w Ĉrodowisku Eclipse
1.13. Stosowanie Anta w Ĉrodowisku NetBeans
1.14. Modyfikowanie kodu XML-a za pomocñ zadania XMLTask
1.15. Konkluzja
83
85
89
89
90
95
2. Przygotowywanie projektu z wykorzystaniem Mavena 2 ........................................97
97
98
99
101
2.1. Rola narzödzia Maven w procesie kompilacji
2.2. Maven i Ant
2.3. Instalacja Mavena
2.4. Kompilacje deklaratywne i model obiektu projektu Mavena
5
2.5. Zrozumieè cykl Ĕycia Mavena 2
2.6. Struktura katalogów Mavena
2.7. Konfigurowanie Mavena pod kñtem naszego Ĉrodowiska
2.8. Zarzñdzanie zaleĔnoĈciami w Mavenie 2
2.9. Poszukiwanie zaleĔnoĈci za poĈrednictwem witryny Maven Repository
2.10. Dziedziczenie i agregacja projektów
2.11. Tworzenie szablonu projektu za pomocñ tzw. archetypów
2.12. Kompilacja kodu
2.13. Testowanie kodu
2.14. Pakowanie i wdraĔanie naszej aplikacji
2.15. WdraĔanie aplikacji z wykorzystaniem narzödzia Cargo
2.16. Stosowanie Mavena w Ĉrodowisku Eclipse
2.17. Stosowanie Mavena w Ĉrodowisku NetBeans
2.18. Dostosowywanie procesu kompilacji do specyficznych potrzeb projektu
za pomocñ wäasnych moduäów rozszerzeþ
2.19. Konfigurowanie repozytorium korporacyjnego za pomocñ narzödzia Archiva
2.20. Konfigurowanie repozytorium korporacyjnego z wykorzystaniem narzödzia
Artifactory
2.21. Stosowanie narzödzia Ant w Mavenie
2.22. Archetypy zaawansowane
2.23. Stosowanie podzespoäów
112
114
115
118
126
127
131
135
136
138
140
144
147
147
154
166
178
183
187
II Narzýdzia kontroli wersji......................................................................193
3. Kontrola wersji z wykorzystaniem systemu CVS ..................................................... 195
195
3.1. Wprowadzenie do systemu CVS
196
3.2. Konfigurowanie repozytorium systemu CVS
196
3.3. Tworzenie nowego projektu w systemie CVS
3.4. WypoĔyczanie projektu
198
3.5. Praca na plikach — aktualizowanie i zatwierdzanie plików z kodem Ēródäowym 200
3.6. Blokowanie repozytorium
204
204
3.7. Praca z mechanizmem zastöpowania säów kluczowych
205
3.8. Praca z plikami binarnymi
207
3.9. Znaczniki systemu CVS
3.10. Tworzenie odgaäözieþ w systemie CVS
208
210
3.11. Scalanie zmian z odgaäözienia
211
3.12. Przeglñdanie historii zmian
213
3.13. Wycofywanie zmian
3.14. Stosowanie CVS-a w systemie Windows
214
6
_
Spis treļci
4. Kontrola wersji z wykorzystaniem systemu Subversion ..........................................217
217
221
221
223
225
227
228
230
231
235
237
239
243
244
246
4.1. Wprowadzenie do systemu Subversion
4.2. Instalacja systemu Subversion
4.3. Typy repozytoriów systemu Subversion
4.4. Konfigurowanie repozytorium systemu Subversion
4.5. Tworzenie nowego projektu w systemie Subversion
4.6. WypoĔyczanie kopii roboczej
4.7. Importowanie istniejñcych plików do repozytorium systemu Subversion
4.8. Zrozumieè adresy URL repozytorium systemu Subversion
4.9. Praca z plikami
4.10. Sprawdzanie bieĔñcej sytuacji — polecenie status
4.11. Rozwiñzywanie konfliktów
4.12. Stosowanie znaczników, odgaäözieþ i operacji scalania
4.13. Przywracanie poprzedniej rewizji
4.14. Blokowanie dostöpu do plików binarnych
4.15. Zdejmowanie i przechwytywanie blokad
4.16. Udostöpnianie zablokowanych plików tylko do odczytu za pomocñ
wäaĈciwoĈci svn:needs-lock
248
249
252
253
257
258
263
4.17. Stosowanie wäaĈciwoĈci
4.18. Historia zmian w systemie Subversion — rejestrowanie zdarzeþ i okreĈlanie
odpowiedzialnoĈci za zmiany
4.19.Konfigurowanie serwera systemu Subversion z wykorzystaniem
serwera svnserve
4.20. Konfigurowanie bezpiecznego serwera svnserve
4.21. Konfigurowanie serwera Subversion z obsäugñ protokoäu WebDAV/DeltaV
4.22. Konfigurowanie bezpiecznego serwera WebDAV/DeltaV
4.23. Dostosowywanie dziaäania systemu Subversion za pomocñ skryptów
przechwytujñcych
264
4.24. Instalacja systemu Subversion w formie usäugi systemu operacyjnego Windows
266
4.25. Sporzñdzanie kopii zapasowej i przywracanie repozytorium systemu Subversion 268
268
4.26. Stosowanie systemu Subversion w Ĉrodowisku Eclipse
4.27. Stosowanie systemu Subversion w Ĉrodowisku NetBeans
275
281
4.28. Stosowanie systemu Subversion w systemie operacyjnym Windows
287
4.29. ćledzenie usterek i kontrola zmian
4.30. Stosowanie systemu Subversion w Ancie
290
292
4.31. Konkluzja
III Ciégĥa integracja .................................................................................. 293
5. Konfigurowanie serwera ciégĥej integracji za pomocé narzýdzia Continuum ......297
297
297
5.1. Wprowadzenie do narzödzia Continuum
5.2. Instalacja serwera narzödzia Continuum
Spis treļci
_
7
5.3. Röczne uruchamianie i zatrzymywanie serwera
5.4. Sprawdzanie stanu serwera
5.5. Uruchamianie serwera narzödzia Continuum w trybie ze szczegóäowymi
301
302
komunikatami
302
303
5.6. Dodawanie grupy projektów
303
5.7. Dodawanie projektu Mavena
306
5.8. Dodawanie projektu Anta
307
5.9. Dodawanie projektu kompilowanego za pomocñ skryptu powäoki
307
5.10. Zarzñdzanie kompilacjami projektu
309
5.11. Zarzñdzanie uĔytkownikami
311
5.12. Konfigurowanie mechanizmów powiadomieþ
311
5.13. Konfigurowanie planowanych kompilacji
314
5.14. Diagnozowanie procesu kompilacji
314
5.15. Konfigurowanie serwera poczty elektronicznej narzödzia Continuum
5.16. Konfigurowanie portów witryny internetowej serwera Continuum
315
5.17. Automatyczne generowanie witryny Mavena za pomocñ narzödzia Continuum 316
317
5.18. Konfigurowanie zadania röcznej kompilacji
5.19. Konkluzja
319
6. Konfigurowanie serwera ciégĥej integracji za pomocé narzýdzia CruiseControl ......... 321
321
322
323
329
336
338
339
340
6.1. Wprowadzenie do narzödzia CruiseControl
6.2. Instalacja narzödzia CruiseControl
6.3. Konfigurowanie projektu Anta
6.4. Powiadamianie czäonków zespoäu za pomocñ mechanizmów publikujñcych
6.5. Konfigurowanie projektu Mavena 2 w narzödziu CruiseControl
6.6. Panel administracyjny narzödzia CruiseControl
6.7. Dodatkowe narzödzia
6.8. Konkluzja
7. LuntBuild — serwer ciégĥej integracji z interfejsem WWW .................................... 341
341
341
343
345
352
353
355
7.1. Wprowadzenie do narzödzia LuntBuild
7.2. Instalowanie narzödzia LuntBuild
7.3. Konfigurowanie serwera LuntBuild
7.4. Dodawanie projektu
7.5. Wykorzystywanie zmiennych projektowych do numerowania wersji
7.6. Diagnostyka wyników kompilacji
7.7. Stosowanie narzödzia LuntBuild w Ĉrodowisku Eclipse
7.8. Raportowanie w systemie LuntBuild o pokryciu testami z wykorzystaniem
narzödzia Cobertura
7.9. Integrowanie narzödzia LuntBuild z Mavenem
7.10. Konkluzja
359
365
370
8
_
Spis treļci
8. Ciégĥa integracja z wykorzystaniem narzýdzia Hudson ...........................................371
371
371
372
373
374
376
381
382
383
385
386
386
387
388
388
390
8.1. Wprowadzenie do narzödzia Hudson
8.2. Instalacja narzödzia Hudson
8.3. Zarzñdzanie katalogiem domowym Hudsona
8.4. Instalacja aktualizacji
8.5. Konfigurowanie Hudsona
8.6. Dodawanie nowego zadania kompilacji
8.7. Organizowanie zadaþ
8.8. Monitorowanie kompilacji
8.9. Przeglñdanie i awansowanie wybranych kompilacji
8.10. Zarzñdzanie uĔytkownikami
8.11. Uwierzytelnianie i bezpieczeþstwo
8.12. Przeglñdanie zmian
8.13. Moduäy rozszerzeþ Hudsona
8.14. ćledzenie wyników testów
8.15. ćledzenie mierników kodu Ēródäowego
8.16. Raportowanie o pokryciu kodu
9. Konfigurowanie platformy natychmiastowej komunikacji
za pomocé serwera Openfire ....................................................................................393
393
9.1. Natychmiastowa komunikacja w projekcie informatycznym
394
9.2. Instalacja serwera Openfire
394
9.3. Konfigurowanie uĔytkowników i kont uĔytkowników serwera Openfire
9.4. Uwierzytelnianie uĔytkowników z wykorzystaniem zewnötrznej bazy danych
396
397
9.5. Uwierzytelnianie uĔytkowników na serwerze POP3
398
9.6. Organizowanie wirtualnych spotkaþ zespoäu z wykorzystaniem czatu grupowego
9.7. Rozszerzanie funkcjonalnoĈci serwera Openfire za pomocñ moduäów rozszerzeþ
400
400
9.8. Stosowanie serwera Openfire z systemem Continuum
401
9.9. Stosowanie serwera Openfire z systemem CruiseControl
9.10. Stosowanie serwera Openfire z narzödziem LuntBuild
402
9.11. Wysyäanie komunikatów Jabbera z poziomu aplikacji Javy
za poĈrednictwem interfejsu API Smack
9.12. Wykrywanie obecnoĈci interfejsu API Smack
9.13. Otrzymywanie wiadomoĈci z wykorzystaniem interfejsu API Smack
402
405
405
IV Testy jednostkowe .............................................................................. 407
10. Testowanie kodu z wykorzystaniem frameworku JUnit .........................................409
409
410
412
10.1. Frameworki JUnit 3.8 i JUnit 4
10.2. Testowanie jednostkowe z wykorzystaniem frameworku JUnit 4
10.3. Konfigurowanie i optymalizacja przypadków testów jednostkowych
Spis treļci
_
9
10.4. Proste testy wydajnoĈci z wykorzystaniem limitów czasowych
10.5. Prosta weryfikacja wystöpowania wyjñtków
10.6. Stosowanie testów sparametryzowanych
10.7. Stosowanie metody assertThat() i biblioteki Hamcrest
10.8. Teorie we frameworku JUnit 4
10.9. Stosowanie frameworku JUnit 4 w projektach Mavena 2
10.10. Stosowanie frameworku JUnit 4 w projektach Anta
10.11. Selektywne wykonywanie testów frameworku JUnit 4 w Ancie
10.12. Testy integracyjne
10.13. Korzystanie z frameworku JUnit 4 w Ĉrodowisku Eclipse
414
415
415
418
421
423
423
426
428
429
11. Testowanie nowej generacji z wykorzystaniem frameworku TestNG ...................433
433
433
435
437
440
443
444
449
451
454
455
456
456
457
11.1. Wprowadzenie do frameworku TestNG
11.2. Tworzenie prostych testów jednostkowych za pomocñ frameworku TestNG
11.3. Definiowanie pakietów testów frameworku TestNG
11.4. Moduä rozszerzenia frameworku TestNG dla Ĉrodowiska Eclipse
11.5. Stosowanie frameworku TestNG w Ancie
11.6. Korzystanie z frameworku TestNG w Mavenie 2
11.7. Zarzñdzanie cyklem Ĕycia testów
11.8. Stosowanie grup testów
11.9. Zarzñdzanie zaleĔnoĈciami
11.10. Testowanie równolegäe
11.11. Parametry testów i testowanie sterowane danymi
11.12. Weryfikacja wyjñtków
11.13. Obsäuga bäödów czöĈciowych
11.14. Ponowne wykonywanie testów zakoþczonych niepowodzeniem
12. Maksymalizacja pokrycia testami za pomocé narzýdzia Cobertura .......................459
459
460
463
465
467
469
471
473
475
12.1. Pokrycie testami
12.2. Uruchamianie narzödzia Cobertura za poĈrednictwem Anta
12.3. Weryfikacja pokrycia kodu testami frameworku TestNG
12.4. Interpretacja raportu narzödzia Cobertura
12.5. Wymuszanie duĔego pokrycia kodu
12.6. Generowanie raportów narzödzia Cobertura w Mavenie
12.7. Integracja testów pokrycia kodu z procesem kompilacji Mavena
12.8. Badanie pokrycia kodu w Ĉrodowisku Eclipse
12.9. Konkluzja
10
_
Spis treļci
V Testy integracyjne, funkcjonalne, obciéŜeniowe i wydajnoļciowe ...477
13. Testowanie aplikacji frameworku Struts
z wykorzystaniem frameworku StrutsTestCase ......................................................481
13.1. Wprowadzenie
481
482
13.2. Testowanie aplikacji frameworku Struts
483
13.3. Wprowadzenie do frameworku StrutsTestCase
483
13.4. Testy obiektów zastöpczych z wykorzystaniem frameworku StrutsTestCase
13.5. Testowanie mechanizmów obsäugi bäödów w aplikacji frameworku Struts
488
489
13.6. Dostosowywanie Ĉrodowiska testowego
489
13.7. Testy wydajnoĈciowe pierwszego stopnia
13.8. Konkluzja
490
14. Testy integracyjne baz danych z wykorzystaniem frameworku DbUnit ................ 491
491
491
493
497
498
506
510
516
520
524
14.1. Wprowadzenie
14.2. Przeglñd
14.3. Struktura frameworku DbUnit
14.4. Przykäadowa aplikacja
14.5. Wypeänianie bazy danych
14.6. Weryfikacja bazy danych
14.7. Zastöpowanie wartoĈci
14.8. Alternatywne formaty zbiorów danych
14.9. Obsäuga niestandardowych testów danych
14.10. Pozostaäe zastosowania
15. Testy wydajnoļciowe z wykorzystaniem frameworku JUnitPerf ...........................533
533
534
536
15.1. Wprowadzenie do frameworku JUnitPerf
15.2. Badanie wydajnoĈci za pomocñ klasy TimedTest
15.3. Symulowanie obciñĔenia za pomocñ klasy LoadTest
15.4. Przeprowadzanie testów wydajnoĈciowych, które nie gwarantujñ
bezpieczeþstwa przetwarzania wielowñtkowego
15.5. Oddzielanie testów wydajnoĈciowych od testów jednostkowych w Ancie
15.6. Oddzielanie testów wydajnoĈciowych od testów jednostkowych w Mavenie
539
540
541
16. Wykonywanie testów obciéŜeniowych i wydajnoļciowych
za pomocé narzýdzia JMeter.....................................................................................543
543
16.1. Wprowadzenie
544
16.2. Instalacja narzödzia JMeter
16.3. Testowanie prostej aplikacji internetowej
544
550
16.4. Projektowanie struktury naszego przypadku testowego
16.5. Rejestrowanie i wyĈwietlanie wyników testu
553
Spis treļci
_
11
16.6. Rejestrowanie przypadku testowego za pomocñ serwera proxy narzödzia JMeter 556
16.7. Testowanie z wykorzystaniem zmiennych
558
560
16.8. Testowanie na wielu komputerach
17. Testowanie usĥug sieciowych za pomocé narzýdzia SoapUI ..................................563
563
563
565
565
567
573
576
578
579
580
581
17.1. Wprowadzenie
17.2. Wprowadzenie do narzödzia SoapUI
17.3. Instalacja narzödzia SoapUI
17.4. Instalacja lokalnej usäugi sieciowej
17.5.Testowanie usäug sieciowych za pomocñ narzödzia SoapUI
17.6. Przeprowadzanie testów obciñĔeniowych za pomocñ narzödzia SoapUI
17.7. Uruchamianie narzödzia SoapUI z poziomu wiersza poleceþ
17.8. Uruchamianie narzödzia SoapUI za poĈrednictwem Anta
17.9. Uruchamianie narzödzia SoapUI za poĈrednictwem Mavena
17.10. Testy ciñgäe
17.11. Konkluzja
18. Profilowanie i monitorowanie aplikacji Javy
za pomocé narzýdzi pakietu Sun JDK .......................................................................583
18.1. Narzödzia profilujñce i monitorujñce pakietu Sun JDK
583
18.2. Nawiñzywanie poäñczenia z aplikacjñ Javy i monitorowanie jej dziaäania
za pomocñ narzödzia JConsole
583
18.3. Monitorowanie zdalnej aplikacji na serwerze Tomcat za pomocñ
narzödzia JConsole
18.4. Wykrywanie i identyfikacja wycieków pamiöci za pomocñ narzödzi pakietu JDK
18.5. Diagnozowanie wycieków pamiöci z wykorzystaniem zrzutów sterty
oraz narzödzi jmap i jhat
18.6. Wykrywanie zakleszczeþ
587
588
593
595
19. Profilowanie aplikacji Javy w ļrodowisku Eclipse ...................................................599
599
599
601
601
602
607
609
610
611
613
613
19.1. Profilowanie aplikacji z poziomu Ĉrodowiska IDE
19.2. Platforma TPTP Ĉrodowiska Eclipse
19.3. Instalacja platformy TPTP
19.4. Platformy TPTP i Java 6
19.5. Podstawowe techniki profilowania z wykorzystaniem platformy TPTP
19.6. Ocena uĔycia pamiöci na podstawie wyników podstawowej analizy pamiöci
19.7. Analiza czasu wykonywania
19.8. WyĈwietlanie statystyk pokrycia
19.9. Stosowanie filtrów zawöĔajñcych uzyskiwane wyniki
19.10. Profilowanie aplikacji internetowej
19.11. Konkluzja
12
_
Spis treļci
20. Testowanie interfejsów uŜytkownika ...................................................................... 615
615
615
642
651
20.1. Wprowadzenie
20.2. Testowanie aplikacji internetowej za pomocñ narzödzia Selenium
20.3. Testowanie graficznych interfejsów Swinga za pomocñ narzödzia FEST
20.4. Konkluzja
VI Narzýdzia pomiaru jakoļci................................................................... 653
21. Wykrywanie i wymuszanie standardów kodowania
za pomocé narzýdzia Checkstyle ..............................................................................657
657
21.1. Wymuszanie standardów kodowania za pomocñ narzödzia Checkstyle
659
21.2. Stosowanie narzödzia Checkstyle w Ĉrodowisku Eclipse
21.3. Modyfikowanie reguä narzödzia Checkstyle w Ĉrodowisku Eclipse
663
21.4. Dostosowywanie reguä narzödzia Checkstyle z wykorzystaniem plików
konfiguracyjnych w formacie XML
21.5. Dostosowywanie pracy narzödzia Checkstyle — reguäy,
bez których moĔemy sobie poradziè, i kilka reguä, z których warto korzystaè
21.6. Stosowanie narzödzia Checkstyle do definiowania reguä
dla nagäówków w kodzie Ēródäowym
21.7. Wstrzymywanie testów narzödzia Checkstyle
21.8. Korzystanie z narzödzia Checkstyle w Ancie
21.9. Korzystanie z narzödzia Checkstyle w Mavenie
665
667
671
672
673
674
22. Wstýpne wykrywanie bĥýdów za pomocé narzýdzia PMD ..................................... 677
677
677
680
681
684
685
686
687
688
691
22.1. Narzödzie PMD i statyczna analiza kodu
22.2. Korzystanie z narzödzia PMD w Ĉrodowisku Eclipse
22.3.Konfiguracja reguä narzödzia PMD w Ĉrodowisku Eclipse
22.4. Wiöcej o zbiorach reguä narzödzia PMD
22.5. Pisanie wäasnych zbiorów reguä narzödzia
22.6. Generowanie raportu narzödzia PMD w Ĉrodowisku Eclipse
22.7. Wstrzymywanie reguä narzödzia PMD
22.8. Wykrywanie praktyki „wytnij i wklej” za pomocñ narzödzia CPD
22.9. Stosowanie narzödzia PMD w Ancie
22.10. Stosowanie narzödzia PMD w Mavenie
23. Wstýpne wykrywanie bĥýdów za pomocé narzýdzia FindBugs ..............................693
693
695
697
698
23.1. FindBugs jako wyspecjalizowany zabójca bäödów
23.2.Stosowanie narzödzia FindBugs w Ĉrodowisku Eclipse
23.3. Wybiórcze zawieszanie stosowania reguä za pomocñ filtrów narzödzia FindBugs
23.4. Stosowanie adnotacji narzödzia FindBugs
Spis treļci
_
13
23.5. Korzystanie z narzödzia FindBugs w Ancie
23.6. Korzystanie z narzödzia FindBugs w Mavenie
23.7. Konkluzja
700
702
704
24. Analiza wyników — póĥautomatyczne przeglédy kodu
za pomocé narzýdzia Jupiter ....................................................................................705
24.1. Wprowadzenie do Jupitera — narzödzia do przeglñdania kodu
w Ĉrodowisku Eclipse
24.2. Instalacja narzödzia Jupiter w Ĉrodowisku Eclipse
24.3.Zrozumieè proces przeglñdów kodu narzödzia Jupiter
24.4. Prowadzenie przeglñdów wäasnego kodu
24.5. Konfiguracja
24.6. Ustawianie domyĈlnych wartoĈci konfiguracyjnych
24.7. Przeglñdy indywidualne
24.8. Przeglñdy zespoäowe
24.9. Faza wprowadzania poprawek
24.10. Wewnötrzne dziaäania Jupitera
24.11. Konkluzja
705
706
706
708
709
713
714
716
719
719
721
25. Koncentrujmy siý na tym, co naprawdý waŜne — narzýdzie Mylyn ......................723
723
724
725
727
25.1. Wprowadzenie do narzödzia Mylyn
25.2. Instalacja rozszerzenia Mylyn
25.3. ćledzenie zadaþ i problemów
25.4. Korzystanie z repozytoriów zadaþ
25.5.Koncentrowanie siö na wybranych zadaniach z wykorzystaniem
mechanizmów zarzñdzania kontekstami
25.6. Korzystanie ze zbiorów zmian Ĉrodowiska Eclipse
25.7. Wspóädzielenie kontekstu z pozostaäymi programistami
25.8. Konkluzja
731
734
736
737
26. Monitorowanie statystyk kompilacji.........................................................................739
739
739
747
748
26.1. Wprowadzenie
26.2. Narzödzie QALab
26.3. Mierzenie iloĈci kodu Ēródäowego za pomocñ moduäu rozszerzenia StatSCM
26.4. Statystyki narzödzia StatSVN w Ancie
VII Narzýdzia do zarzédzania problemami ..............................................751
27. Bugzilla ......................................................................................................................753
753
753
757
27.1. Wprowadzenie do narzödzia Bugzilla
27.2. Instalacja narzödzia Bugzilla
27.3. Konfigurowanie Ĉrodowiska narzödzia Bugzilla
14
_
Spis treļci
27.4. Zarzñdzanie kontami uĔytkowników
758
27.5. Ograniczanie dostöpu do bazy danych z wykorzystaniem grup uĔytkowników 760
762
27.6. Konfigurowanie produktu
764
27.7. ćledzenie postöpu z wykorzystaniem tzw. kamieni milowych
27.8. Zarzñdzanie grupami produktów z wykorzystaniem klasyfikacji
764
765
27.9. Przeszukiwanie bäödów
767
27.10. Tworzenie nowego bäödu
768
27.11. Cykl Ĕycia bäödu reprezentowanego w systemie Bugzilla
27.12. Tworzenie harmonogramu rozsyäania powiadomieþ (pojökiwania)
770
771
27.13. Dostosowywanie pól systemu Bugzilla do potrzeb konkretnego projektu
27.14. Konkluzja
772
28. Trac — lekkie zarzédzanie projektami ..................................................................... 773
773
774
776
778
779
780
781
783
28.1. Wprowadzenie do narzödzia Trac
28.2. Instalacja narzödzia Trac
28.3. Definiowanie projektu narzödzia Trac
28.4. Uruchamianie narzödzia Trac w formie autonomicznego serwera
28.5 Konfiguracja polecenia tracd jako usäugi systemu Windows
28.6. Instalacja narzödzia Trac na serwerze Apache
28.7. Administrowanie witrynñ internetowñ Traca
28.8. Zarzñdzanie kontami uĔytkowników
28.9. Dostosowywanie witryny internetowej narzödzia Trac
— korzystanie z funkcji witryn typu wiki
28.10. Stosowanie systemu zarzñdzania biletami Traca
28.11. Aktualizowanie bäödów reprezentowanych w narzödziu Trac na podstawie
zawartoĈci repozytorium systemu Subversion
28.12. Modyfikowanie pól biletów Traca
28.13. Konfigurowanie powiadomieþ wysyäanych pocztñ elektronicznñ
28.14. Raportowanie z wykorzystaniem zapytaþ i raportów Traca
28.15. Zarzñdzanie postöpami prac za pomocñ map drogowych
i diagramów linii czasu
28.16. Przeglñdanie repozytorium z kodem Ēródäowym
28.17. Stosowanie kanaäów RSS i formatu iCalendar
28.18. Dostosowywanie stron witryny wiki za pomocñ skryptów Pythona
28.19. Konkluzja
786
790
794
795
797
797
800
802
802
805
806
VIII Narzýdzia do dokumentacji technicznej ............................................ 807
29. Komunikacja w ramach zespoĥu projektowego
za poļrednictwem witryny Mavena 2 ......................................................................809
809
29.1.Witryna internetowa Mavena 2 jako narzödzie komunikacyjne
29.2. Konfigurowanie mechanizmu generowania witryny o projekcie Mavena
810
Spis treļci
_
15
29.3. Wäñczanie do witryny Mavena raportów generowanych przez inne narzödzia
29.4. Tworzenie dedykowanego projektu witryny Mavena
29.5. Definiowanie szkicu witryny
29.6. Architektura mechanizmu generujñcego witryny Mavena
29.7. Stosowanie fragmentów kodu
29.8. Modyfikowanie wyglñdu i sposobu obsäugi witryny Mavena
29.9. Udostöpnianie witryny
815
819
821
822
826
827
830
30. Automatyczne generowanie dokumentacji technicznej .........................................833
833
833
841
30.1. Wprowadzenie
30.2. Wizualizacja struktury bazy danych za pomocñ narzödzia SchemaSpy
30.3. Generowanie dokumentacji kodu Ēródäowego za pomocñ Doxygena
30.4. Umieszczanie diagramów notacji UML w dokumentacji narzödzia Javadoc
z wykorzystaniem narzödzia UmlGraph
30.5. Konkluzja
850
854
Bibliografia ...........................................................................................................................855
Skorowidz............................................................................................................................. 857
16
_
Spis treļci
ROZDZIAĤ 10.
Testowanie kodu
z wykorzystaniem frameworku JUnit
10.1. Frameworki JUnit 3.8 i JUnit 4
JUnit w chwili wprowadzenia na rynek byä naprawdö rewolucyjnym oprogramowaniem
— od tego czasu powstaäo mnóstwo przydatnych rozszerzeþ tego frameworku uäatwiajñcych
nam wykonywanie testów jednostkowych w najbardziej wyspecjalizowanych obszarach.
Wiele z tych rozszerzeþ do tej pory bazuje na frameworku JUnit 3.x. Kilka takich rozszerzeþ
omówimy w dalszej czöĈci tej ksiñĔki. W niniejszym podrozdziale spróbujemy sobie przy-
pomnieè framework 3.8, aby lepiej rozumieè dalszy materiaä poĈwiöcony zmianom wprowadzo-
nym w nowszych frameworkach, jak JUnit 4 czy TestNG (patrz rozdziaä 20.).
We frameworku JUnit 3 pisane przez nas testy jednostkowe majñ postaè klas Javy okreĈlanych
mianem przypadków testowych. Wszystkie przypadki testowe tego frameworku muszñ rozsze-
rzaè klasö TestCase. Testy jednostkowe implementujemy w formie metod tych klas — definiujñc
te metody, musimy przestrzegaè specjalnych konwencji nazewniczych: metody testowe muszñ
zwracaè void, nie mogñ pobieraè Ĕadnych parametrów, a ich nazwy muszñ siö rozpoczynaè
od säowa test. TakĔe nazwy klas testowych muszñ byè zgodne z prostñ konwencjñ — nazwa
kaĔdej takiej klasy musi siö koþczyè säowem Test.
PoniĔej przedstawiono prostñ klasö testowñ frameworku JUnit 3.8 testujñcñ innñ klasö, która
z kolei odpowiada za obliczanie podatku od wartoĈci dodanej (ang. Value Added Tax — VAT),
nazywanego teĔ podatkiem od towarów i usäug. Przyjmijmy, Ĕe podstawowa stawka podatku
VAT wynosi 22 procent. Nasz klasa testu jednostkowego moĔe mieè nastöpujñcñ postaè:
public class PriceCalculatorTest extends TestCase {
public void testCalculateVAT() {
calculator = new PriceCalculator();
double amountWithVat = calculator.calculatePriceWithVAT(100.00);
assertEquals( Podstawowa stawka VAT wynosi 22 , 122.00, amountWithVat, 0.0);
}
}
Klasa bazowa TestCase oferuje mnóstwo metod z rodziny assert: assertEquals(), assert
´True(), assertNotNull() i wiele innych. WäaĈnie wymienione metody skäadajñ siö na jñdro
testów jednostkowych, poniewaĔ za ich poĈrednictwem wykonujemy nasze testy. Metody
assert säuĔñ do sprawdzania, czy uzyskiwane wyniki sñ zgodne z wartoĈciami oczekiwanymi.
409
Za poĈrednictwem pierwszego parametru metody assert moĔemy przekazaè opcjonalny
komunikat, który w przyszäoĈci powinien nam uäatwiè identyfikacjö bäödu (szczególnie jeĈli
korzystamy z duĔej liczby testów jednostkowych).
Metody setUp() i tearDown() (zwróèmy uwagö na wielkie litery!) moĔna przykryè wersjami
odpowiednio inicjalizujñcymi i przywracajñcymi (przed i po kaĔdym teĈcie) stan Ĉrodowiska
testowego, w którym wykonujemy nasz kod. JeĈli na przykäad korzystamy z wielu przypadków
testowych operujñcych na obiekcie calculator, moĔemy zdecydowaè o jego jednorazowym
utworzeniu w kodzie metody setUp():
public class PriceCalculatorTest extends TestCase {
PriceCalculator calculator;
protected void setUp() throws Exception {
calculator = new PriceCalculator();
}
public void testCalculateVAT() {
double amountWithVat = calculator.calculatePriceWithVAT(100.00);
assertEquals( Podstawowa stawka VAT wynosi 22 , 122.00, amountWithVat, 0.0);
}
// Pozostaáe testy obiektu calculator...
}
MoĔliwoĈci frameworku JUnit 3 oczywiĈcie nie ograniczajñ siö do zaprezentowanych mecha-
nizmów, jednak uzyskana wiedza o architekturze tego frameworku powinna w zupeänoĈci
wystarczyè do zrozumienia innowacji wprowadzonych w nowszych frameworkach i rozszerzeþ
frameworku JUnit 3 omawianych w pozostaäych rozdziaäach. Framework JUnit 4 pod wieloma
wzglödami przewyĔsza framework JUnit 3, jednak wersja 3.8 wciñĔ cieszy siö duĔñ popularno-
Ĉciñ, a wiele atrakcyjnych moduäów rozszerzeþ nadal nie doczekaäo siö aktualizacji do wersji
4. W kolejnych podrozdziaäach tego rozdziaäu skoncentrujemy siö wyäñcznie na frameworku
JUnit 4.
10.2. Testowanie jednostkowe
z wykorzystaniem frameworku JUnit 4
W Ĉwiecie frameworków testów jednostkowych JUnit jest de facto standardem. Jest powszechnie
stosowany i doskonale znany niemal kaĔdemu programiĈcie. JUnit oferuje teĔ wiele przydatnych
rozszerzeþ stworzonych z myĈlñ o bardziej wyspecjalizowanych procesach testowych. Frame-
work JUnit (w oryginalnej wersji autorstwa Kenta Becka i Ericha Gammy) jest uwaĔany
za rozwiñzanie, które (przynajmniej teoretycznie) spopularyzowaäo praktyki testów jednostko-
wych wĈród programistów Javy. Okazuje siö jednak, Ĕe wskutek spadku dynamiki zmian
wprowadzanych w podstawowym interfejsie API w ostatnich latach powstaäo i zyskaäo
popularnoĈè kilka innych, jeszcze bardziej innowacyjnych frameworków, na przykäad TestNG
(patrz rozdziaä 20.).
JUnit 3 nakäada na programistów wiele ograniczeþ, które nie znajdujñ Ĕadnego uzasadnienia
w dobie Javy 5, adnotacji i paradygmatu odwrócenia sterowania (ang. Inversion of Control — IoC).
We frameworku JUnit 3 klasy testów muszñ rozszerzaè klasö bazowñ samego frameworku
JUnit, a testy muszñ byè definiowane zgodnie ze specjalnymi konwencjami nazewnictwa
— nie moĔemy uĔyè w roli klasy testu dowolnej klasy Javy. Klasy testów frameworku JUnit 3
410
_
Rozdziaĥ 10. Testowanie kodu z wykorzystaniem frameworku JUnit
sñ inicjalizowane za kaĔdym razem, gdy wykonujemy jakiĈ test, co znacznie utrudnia refaktory-
zacjö i optymalizacjö kodu testowego. JUnit 3 w Ĕaden sposób nie wspiera na przykäad testowa-
nia sterowanego danymi (czyli wykonywania testów na danych pochodzñcych z zewnñtrz).
We frameworku JUnit 3 brakuje teĔ takich mechanizmów jak funkcje zarzñdzania zaleĔnoĈciami
pomiödzy testami czy grupami testów.
JUnit 4 jest niemal caäkowicie przebudowanym interfejsem API JUnit, który ma na celu wyko-
rzystanie postöpu obserwowanego w Ĉwiecie technologii Javy w ciñgu ostatnich kilku lat.
Framework JUnit 4 jest prostszy, äatwiejszy w uĔyciu i bardziej elastyczny od swojego poprzed-
nika; oferuje teĔ kilka nowych funkcji! JUnit 4 wprowadza mnóstwo nowych mechanizmów,
które mogñ nam znacznie uäatwiè pisanie testów jednostkowych, w tym obsäugö adnotacji
i bardziej elastyczny model inicjalizacji klas testów. We frameworku JUnit test moĔe mieè
postaè dowolnej klasy Javy, a metody testów nie muszñ byè zgodne z Ĕadnymi konwencjami
nazewniczymi.
SprawdĒmy wiöc, jak nasze testy kalkulatora podatkowego (patrz podrozdziaä 10.1) wyglñdaäyby
we frameworku JUnit 4:
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
public class PriceCalculatorTest {
@Test
public void calculateStandardVAT() {
PriceCalculator calculator = new PriceCalculator();
double vat = calculator.calculatePriceWithVAT(100.00);
assertEquals(vat, 122.00 , 0.0);
}
@Test
public void calculateReducedVAT() {
PriceCalculator calculator = new PriceCalculator();
double vat = calculator.calculatePriceWithReducedVAT(100.00);
assertEquals(vat, 105.00 , 0.0);
}
}
Warto w pierwszej kolejnoĈci zwróciè uwagö na brak koniecznoĈci rozszerzania konkretnej
klasy przez przypadki testowe frameworku JUnit 4 (takie wymaganie obowiñzywaäo we frame-
worku JUnit 3). Podobnie jak TestNG, framework JUnit 4 wykorzystuje adnotacje do oznaczania
metod, które powinny byè traktowane jako testy jednostkowe. Za testy jednostkowe uwaĔa siö
wszystkie metody oznaczone adnotacjñ @Test. JUnit 4 co prawda nie narzuca nam Ĕadnej kon-
wencji nazewniczej (metody testów nie muszñ siö rozpoczynaè od säowa test, jak testThis()
czy testThat()), ale wymaga, by metody testów jednostkowych zwracaäy void i nie pobieraäy
Ĕadnych parametrów. Teoretycznie moĔna by nawet umieszczaè testy jednostkowe w tej
samej klasie, w której znajduje siö testowany kod, jednak w praktyce lepszym rozwiñzaniem
jest definiowanie kodu testowego w odröbnych klasach.
Klasa org.junit.Assert zawiera tradycyjne metody assert frameworku JUnit 3.x, do których
zdñĔyliĈmy siö przyzwyczaiè i które tak lubimy. We frameworku JUnit 3 metody assert byäy
definiowane w klasie TestCase, czyli klasie bazowej dla wszystkich klas testów tego frameworku
— dziöki temu moĔna byäo z nich korzystaè w dowolnych testach. Z zupeänie innñ sytuacjñ
mamy do czynienia w przypadku frameworku JUnit 4, gdzie klasy testów nie muszñ dzie-
dziczyè po klasie TestCase. Nie ma jednak powodów do zmartwieþ — moĔemy dla tej klasy
10.2. Testowanie jednostkowe z wykorzystaniem frameworku JUnit 4
_
411
uĔyè operacji statycznego importowania, aby korzystaè z niezbödnych klas assert (w tym
assertEquals, assertNotNull itp.; patrz przykäady w dalszej czöĈci tego rozdziaäu) w dokäadnie
taki sam sposób jak w testach jednostkowych frameworku JUnit 3.x.
Alternatywnym rozwiñzaniem jest stosowanie wyraĔeþ assert dostöpnych w Javie 5:
assert (vat == 100*PriceCalculator.DEFAULT_VAT_RATE);
WyraĔenie w tej formie sprawia wraĔenie bardziej eleganckiego, jednak musimy pamiötaè
o pewnej puäapce — Java ignoruje nasze wyraĔenia assert, chyba Ĕe w wierszu poleceþ uĔyjemy
opcji -ea (od ang. enable assertions).
10.3. Konfigurowanie i optymalizacja przypadków
testów jednostkowych
Jak kaĔdy kod Ēródäowy, testy jednostkowe wymagajñ efektywnego kodowania i — w razie
koniecznoĈci — refaktoryzacji. Framework JUnit 4 oferuje kilka adnotacji, które mogñ nam
to zadanie bardzo uäatwiè. Adnotacja @Before wskazuje metodö, która musi byè wywoäana
przed kaĔdym testem, czyli w praktyce zastöpuje znanñ z frameworku JUnit 3.x metodö
setup(). MoĔemy teĔ uĔyè adnotacji @After do wskazania metod przywracajñcych stan
Ĉrodowiska testowego po kaĔdym wykonanym teĈcie. W tym przypadku metoda initialize()
bödzie wywoäywana przed, a metoda tidyup() po kaĔdym teĈcie jednostkowym:
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
public class PriceCalculatorTest {
private PriceCalculator calculator;
@Before
public void initialize() {
calculator = new PriceCalculator();
}
@Test
public void calculateStandardVAT() {
PriceCalculator calculator = new PriceCalculator();
double vat = calculator.calculatePriceWithVAT(100.00);
assertEquals(vat, 122.00 , 0.0);
}
@Test
public void calculateReducedVAT() {
PriceCalculator calculator = new PriceCalculator();
double vat = calculator.calculatePriceWithReducedVAT(100.00);
assertEquals(vat, 105 , 0.0);
}
@After
public void tidyup() {
calculator.close();
calculator = null;
}
}
412
_
Rozdziaĥ 10. Testowanie kodu z wykorzystaniem frameworku JUnit
Takie rozwiñzanie wciñĔ nie jest optymalne. JUnit oferuje kilka innych adnotacji, których
moĔna z powodzeniem uĔywaè do dodatkowego doskonalenia kodu naszych testów jednostko-
wych. W pewnych sytuacjach warto poprawiè efektywnoĈè testów przez skonfigurowanie
niektórych zasobów przed wykonaniem któregokolwiek z testów jednostkowych zdefinio-
wanych w danej klasie i ich zwolnienie po zakoþczeniu wykonywania testów tej klasy. Cel ten
moĔna osiñgnñè odpowiednio za pomocñ adnotacji @BeforeClass i @AfterClass. Metody
oznaczone adnotacjñ @BeforeClass zostanñ wywoäane tylko raz, przed wykonaniem którego-
kolwiek z testów jednostkowych definiowanych przez danñ klasö. Jak äatwo siö domyĈliè,
metody oznaczone adnotacjñ @AfterClass zostanñ wywoäane dopiero po zakoþczeniu wszyst-
kich testów. W powyĔszym przykäadzie obiekt calculator zostaäby utworzony tylko raz (na
poczñtku testów jednostkowych) i zniszczony dopiero po wykonaniu wszystkich testów.
Klasö tö moĔna uzupeäniè o metodö reset() wywoäywanñ przed kaĔdym testem jednostkowym
i odpowiedzialnñ za kaĔdorazowe ponowne inicjalizowanie testowanego obiektu calculator.
MoĔliwy sposób implementacji tak zoptymalizowanej klasy testów jednostkowych przedstawio-
no poniĔej:
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
public class PriceCalculatorTest {
private PriceCalculator calculator;
@BeforeClass
public void initialize() {
calculator = new PriceCalculator();
}
@Before
public void resetCalculator() {
calculator.reset();
}
@Test
public void calculateStandardVAT() {
PriceCalculator calculator = new PriceCalculator();
double vat = calculator.calculatePriceWithVAT(100.00);
assertEquals(vat, 122.00 , 0.0);
}
@Test
public void calculateReducedVAT() {
PriceCalculator calculator = new PriceCalculator();
double vat = calculator.calculatePriceWithReducedVAT(100.00);
assertEquals(vat, 105 , 0.0);
}
@AfterClass
public void tidyup() {
calculator.close();
}
}
10.3. Konfigurowanie i optymalizacja przypadków testów jednostkowych
_
413
10.4. Proste testy wydajnoļci
z wykorzystaniem limitów czasowych
Jednym z najprostszych sposobów przeprowadzania testów wydajnoĈci jest sprawdzanie, czy
okreĈlony test zawsze jest wykonywany w okreĈlonych ramach czasowych. Takie rozwiñzanie
bywa szczególnie przydatne w przypadku zapytaþ wykonywanych na bazie danych z uĔyciem
takich narzödzi odwzorowaþ obiektowo-relacyjnych jak Hibernate. Nawet proste bäödy
w plikach odwzorowaþ tego narzödzia mogñ skutkowaè znacznie wydäuĔonymi czasami
odpowiedzi (takĔe w przypadku stosunkowo prostych zapytaþ). W przeciwieþstwie do trady-
cyjnego testu jednostkowego, test z okreĈlonym limitem czasowym umoĔliwia wykrywanie
tego rodzaju bäödów.
Tego rodzaju testy sprawdzajñ siö takĔe w roli mechanizmów wykrywajñcych pötle nieskoþczo-
ne, chociaĔ wskazanie fragmentów kodu, które mogñ zawieraè tego rodzaju konstrukcje, jest
oczywiĈcie nieporównanie trudniejsze.
Opisanñ technikö zintegrowano bezpoĈrednio z adnotacjñ @Test, która umoĔliwia ustawianie
górnego limitu czasu, w którym dany test musi siö zakoþczyè — w przeciwnym razie po upäy-
niöciu tego czasu test koþczy siö bäödem. W tym celu naleĔy zdefiniowaè parametr timeout
(reprezentujñcy limit czasowy wyraĔony w milisekundach) adnotacji @Test:
@Test(timeout=100)
public void lookupVAT() {
double vat = calculator.lookupRateForYear(2006);
assertEquals(vat, VAT_RATE_IN_2006 , 0.0);
}
JeĈli uĔyte zapytanie zajmuje testowanej funkcji wiöcej niĔ 100 milisekund, nasz test koþczy
siö niepowodzeniem:
Testsuite: com.wakaleo.jpt.alexandria.services.PriceCalculatorTest
Tests run: 3, Failures: 0, Errors: 1, Time elapsed: 0.136 sec
Testcase: calculateStandardVAT took 0.009 sec
Testcase: lookupVAT took 0.128 sec
Caused an ERROR
test timed out after 100 milliseconds
java.lang.Exception: test timed out after 100 milliseconds
W przypadku niektórych metod, od których oczekujemy wysokiej wydajnoĈci i których
efektywnoĈè ma kluczowe znaczenie dla funkcjonowania naszej aplikacji, warto dodatkowo
sprawdziè, czy oferowana przepustowoĈè speänia nasze oczekiwania. OczywiĈcie im mniejsza
bödzie wartoĈè limitu czasowego, tym wiöksze bödzie ryzyko wystñpienia sytuacji, w której
jakiĈ czynnik zewnötrzny spowalniajñcy nasze testy doprowadzi do nieuzasadnionego przekro-
czenia tego limitu. Na przykäad w poniĔszym przypadku testowym sprawdzamy, czy Ĉredni
czas wykonywania metody calculateInterest() nie przekracza milisekundy:
@Test(timeout=50)
public void perfTestCalculateInterest() {
InterestCalculator calc = new InterestCalculatorImpl();
for(int i = 0 ; i 50; i++) {
calc.calculateInterest(principal, interestRate, startDate, periodInDays);
}
}
414
_
Rozdziaĥ 10. Testowanie kodu z wykorzystaniem frameworku JUnit
Tego rodzaju testy gwarantujñ nam, Ĕe uzyskiwane wyniki bödñ zbliĔone do rzeczywistoĈci
i Ĕe badane metody nie sñ szczególnie powolne — nie powinniĈmy byè zbyt wymagajñcy.
10.5. Prosta weryfikacja wystýpowania wyjétków
W niektórych przypadkach warto sprawdzaè, czy w okreĈlonych okolicznoĈciach nastöpuje
prawidäowe generowanie wyjñtków. We frameworku JUnit 3.x to doĈè pracochäonne zadanie
wiñĔe siö z koniecznoĈciñ przechwytywania wyjñtku — jeĈli wyjñtek uda siö przechwyciè,
przyjmujemy, Ĕe test zakoþczyä siö pomyĈlnie; w przeciwnym razie test koþczy siö niepowo-
dzeniem. We frameworku JUnit 4 mamy do dyspozycji parametr expected adnotacji @Test,
któremu naleĔy przypisaè klasö oczekiwanego wyjñtku (wäaĈnie ten wyjñtek powinien zostaè
wygenerowany zgodnie z naszym planem). W poniĔszym (doĈè maäo realistycznym) przykäadzie
oczekujemy od aplikacji wygenerowania wyjñtku IllegalArgumentException, jeĈli dany rok
jest mniejszy od przyjötego progu. We frameworku JUnit 4 odpowiedni test jest bardzo prosty:
@Test(expected = IllegalArgumentException.class)
public void lookupIllegalVATYear() {
double vat = calculator.lookupRateForYear(1066);
}
JeĈli badana metoda nie wygeneruje wyjñtku IllegalArgumentException, nasz test zakoþczy
siö niepowodzeniem:
Testsuite: com.wakaleo.jpt.alexandria.services.PriceCalculatorTest
Tests run: 3, Failures: 1, Errors: 0, Time elapsed: 0.114 sec
Testcase: calculateStandardVAT took 0.009 sec
Testcase: lookupVAT took 0.01 sec
Testcase: lookupIllegalVATYear took 0.003 sec
FAILED
Expected exception: java.lang.IllegalArgumentException
junit.framework.AssertionFailedError: Expected exception:
java.lang.IllegalArgumentException
10.6. Stosowanie testów sparametryzowanych
Pisanie testów jednostkowych jest doĈè nuĔñce, zatem wielu programistów próbuje iĈè na skróty.
Okazuje siö jednak, Ĕe od pewnych czynnoĈci nie uciekniemy — dobre testy jednostkowe
muszñ weryfikowaè dziaäanie funkcji biznesowych dla rozmaitych danych, jak przypadki
skrajne, klasy danych itp. Ten sam test moĔe siö zakoþczyè pomyĈlnie dla jednego zbioru danych,
by chwilö póĒniej wykazaè powaĔne bäödy dla innego zbioru. JeĈli jednak programista musi
napisaè odröbny przypadek testowy dla kaĔdej wartoĈci (zgodnie z najlepszymi praktykami
testowania), najprawdopodobniej jego kod bödzie weryfikowaä stosunkowo niewielki zbiór
wartoĈci. CzyĔ nie byäoby wspaniale, gdybyĈmy mogli wielokrotnie wykonywaè ten sam test
jednostkowy z wykorzystaniem róĔnych danych?
Okazuje siö, Ĕe JUnit 4 oferuje dopracowany mechanizm uäatwiajñcy nam testowanie kodu na
dowolnych zbiorach danych. Za pomocñ tego mechanizmu moĔemy zdefiniowaè kolekcjö
danych testowych i wymusiè jej automatyczne wypeänianie w ramach naszych metod testów
jednostkowych. Przeanalizujmy teraz prosty przykäad. PrzypuĈèmy, Ĕe musimy napisaè klasö
wyznaczajñcñ wysokoĈè podatku dochodowego dla okreĈlonych dochodów we wskazanym
roku. Interfejs naszej klasy biznesowej moĔe mieè nastöpujñcñ postaè:
10.6. Stosowanie testów sparametryzowanych
_
415
public interface TaxCalculator {
public double calculateIncomeTax(int year, double taxableIncome);
}
Wyznaczanie podatku dochodowego z reguäy wymaga wykonywania kilku nieäatwych obliczeþ.
W wiökszoĈci krajów stosuje siö system podatków progresywnych, gdzie stawki podatkowe
rosnñ wraz ze wzrostem opodatkowanych dochodów. Stawki definiuje siö dla odröbnych
przedziaäów dochodów. Co wiöcej, same progi podatkowe (a wiöc takĔe przedziaäy dochodów)
nierzadko sñ zmieniane w kolejnych latach. W przypadku aplikacji odpowiedzialnej za tego
rodzaju obliczenia niezwykle waĔne jest przetestowanie wartoĈci z kaĔdego przedziaäu, a takĔe
przypadków skrajnych. W tej sytuacji powinniĈmy opracowaè kolekcjö danych testowych
obejmujñcych moĔliwie wiele dochodów, lat i oczekiwanych obciñĔeþ podatkowych. SprawdĒmy,
jak moĔna to zrobiè.
JUnit 4 umoĔliwia nam definiowanie zbiorów danych testowych, które moĔna nastöpnie
przekazywaè do naszych testów jednostkowych. W tym przypadku musimy przetestowaè
róĔne dochody podlegajñce opodatkowaniu w róĔnych przedziaäach podatkowych. W prezento-
wanym przykäadzie skoncentrujemy siö tylko na roku 2006, jednak w rzeczywistej aplikacji
powinniĈmy poddaè testom wiele lat podatkowych. Nasze zbiory testowe bödñ wiöc zawieraè
po trzy wartoĈci: opodatkowane dochody, rok podatkowy oraz prawidäowñ wysokoĈè podatku
dochodowego.
Korzystanie z tych danych testowych wymaga skonfigurowania sparametryzowanej klasy
testowej. MoĔe to byè zwykäa klasa testowa z konstruktorem otrzymujñcym na wejĈciu kilka
parametrów, a konkretnie po jednym parametrze dla kaĔdej wartoĈci naszego zbioru danych.
Oznacza to, Ĕe w analizowanym przypadku wspomniany konstruktor bödzie pobieraä trzy
parametry: opodatkowane dochody, rok podatkowy i oczekiwanñ wysokoĈè podatku docho-
dowego. Sparametryzowana klasa testowa z reguäy obejmuje zmienne skäadowe reprezentu-
jñce kaĔde z tych pól. Za inicjalizacjö tych pól odpowiada konstruktor, a wäaĈciwe metody
testów jednostkowych wykorzystujñ je w czasie testowania.
JUnit tworzy odröbny obiekt naszej klasy testów dla kaĔdego wiersza danych testowych,
po czym wykonuje na tych danych testy jednostkowe (metody) tej klasy. Oznacza to, Ĕe jeĈli
nasze dane testowe obejmujñ 20 wierszy, JUnit utworzy obiekt naszej klasy 20 razy i kaĔdorazo-
wo wykona testy jednostkowe na innym wierszu tego zbioru danych.
SprawdĒmy teraz, jak moĔna ten mechanizm zaimplementowaè. Kompletny kod naszej klasy
testowej (dla fikcyjnych progów podatkowych) przedstawiono poniĔej:
@RunWith(Parameterized.class)
public class TaxCalculatorTest {
@Parameters
public static Collection data() {
return Arrays.asList(new Object[][]{
/* Dochód Rok Podatek */
{ 0.00, 2006, 0.00},
{ 10000.00, 2006, 1950.00},
{ 20000.00, 2006, 3900.00},
{ 38000.00, 2006, 7410.00},
{ 38001.00, 2006, 7410.33},
{ 40000.00, 2006, 8070.00},
{ 60000.00, 2006, 14670.00},
{100000.00, 2006, 30270.00},
});
}
416
_
Rozdziaĥ 10. Testowanie kodu z wykorzystaniem frameworku JUnit
private double revenue;
private int year;
private double expectedTax;
public TaxCalculatorTest(double input, int year, double expectedTax) {
this.revenue = revenue;
this.year = year;
this.expectedTax = expectedTax;
}
@Test public void calculateTax() {
TaxCalculator calculator = getTaxCalculator();
double calculatedTax = calculator.calculateIncomeTax(year, revenue);
assertEquals(expectedTax, calculatedTax);
}
private TaxCalculator getTaxCalculator() {
TaxCalculator calculator = new TaxCalculatorImpl();
return calculator;
}
}
Przeanalizujmy teraz poszczególne fragmenty tej klasy. Po pierwsze, musimy uĔyè adnotacji
@RunWith wskazujñcej na klasö Parameterized, aby zasygnalizowaè frameworkowi JUnit,
Ĕe nasza klasa testowa zawiera sparametryzowane przypadki testowe:
@RunWith(Parameterized.class)
public class TaxCalculatorTest {...
Musimy teraz sporzñdziè kolekcjö naszych danych testowych. W tym celu definiujemy funkcjö
oznaczonñ adnotacjñ @Parameters i zwracajñcñ dane testowe w formie kolekcji. Dane testowe
wewnötrznie czösto majñ postaè listy tablic. W naszym przypadku dane testowe przyjmujñ
formö listy tablic wartoĈci, gdzie kaĔda tablica obejmuje trzy elementy: dochód, rok i oczekiwanñ
wysokoĈè podatku dochodowego (od danego dochodu osiñgniötego we wskazanym roku
podatkowym):
@Parameters
public static Collection data() {
return Arrays.asList(new Object[][]{
/* Dochód Rok Podatek */
{ 0.00, 2006, 0.00},
{ 10000.00, 2006, 1950.00},
{ 20000.00, 2006, 3900.00},
{ 38000.00, 2006, 7410.00},
{ 38001.00, 2006, 7410.33},
{ 40000.00, 2006, 8070.00},
{ 60000.00, 2006, 14670.00},
{100000.00, 2006, 30270.00},
});
}
Jak juĔ wspomniano, kiedy framework JUnit 4 wykonuje naszñ klasö testowñ, w rzeczywistoĈci
tworzy po jednym obiekcie tej klasy dla kaĔdego wiersza kolekcji danych testowych. W tej
sytuacji musimy zdefiniowaè zmienne skäadowe reprezentujñce te wartoĈci, a takĔe konstruk-
tor publiczny odpowiedzialny za ich inicjalizacjö, aby framework JUnit mógä tworzyè kolejne
obiekty z wäaĈciwymi danymi testowymi:
private double revenue;
private int year;
private double expectedTax;
10.6. Stosowanie testów sparametryzowanych
_
417
public TaxCalculatorTest(double revenue, int year, double expectedTax) {
this.revenue = revenue;
this.year = year;
this.expectedTax = expectedTax;
}
MoĔemy teraz przetestowaè nasz kod z wykorzystaniem tych wartoĈci:
@Test
public void calculateTax() {
TaxCalculator calculator = getTaxCalculator();
double calculatedTax = calculator.calculateIncomeTax(year, revenue);
assertEquals(expectedTax, calculatedTax);
}
Kiedy uruchomimy te testy jednostkowe, okaĔe siö, Ĕe nasze testy zostanñ wykonane wielokrot-
nie — osobno dla kaĔdego wiersza uĔytych danych testowych:
Testsuite: com.wakaleo.jpt.alexandria.services.TaxCalculatorTest
Tests run: 8, Failures: 0, Errors: 0, Time elapsed: 0.119 sec
Testcase: calculateTax[0] took 0.012 sec
Testcase: calculateTax[1] took 0.001 sec
Testcase: calculateTax[2] took 0.002 sec
Testcase: calculateTax[3] took 0.001 sec
Testcase: calculateTax[4] took 0.001 sec
Testcase: calculateTax[5] took 0.001 sec
Testcase: calculateTax[6] took 0.002 sec
Testcase: calculateTax[7] took 0.003 sec
Warto pamiötaè o moĔliwoĈci umieszczania wielu testów jednostkowych w jednej sparame-
tryzowanej klasie testów (podobnie jak w przypadku tradycyjnych klas testów jednostkowych).
KaĔda metoda testu jednostkowego bödzie wywoäywana osobno dla kaĔdego wiersza danych
testowych.
10.7. Stosowanie metody assertThat()
i biblioteki Hamcrest
We frameworku JUnit 4.4 wprowadzono nowe pojöcie dla wyraĔeþ asercji, aby intencje
programistów byäy bardziej zrozumiaäe i äatwiejsze w interpretacji. Opisywana koncepcja,
której oryginalnym pomysäodawcñ byä Joe Walnes1, sprowadza siö do stosowania metody
assertThat äñcznie ze zbiorem wyraĔeþ dopasowujñcych (okreĈlanych teĔ mianem ograniczeþ
lub predykatów), co w wielu przypadkach znacznie poprawia czytelnoĈè testów. Na przykäad
poniĔsza klasa sprawdza, czy w danej sytuacji testowana funkcja wyznacza zerowy podatek
dochodowy:
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
public class TaxCalculatorTest {
@Test
public void calculateTax() {
TaxCalculator calculator = getTaxCalculator();
1 Patrz http://joe.truemesh.com/blog/000511.html.
418
_
Rozdziaĥ 10. Testowanie kodu z wykorzystaniem frameworku JUnit
double calculatedTax = calculator.calculateIncomeTax(2007, 0);
assertThat(calculatedTax, is(0.0));
}
}
Wywoäanie assertThat(calculatedTax, is(0.0)) jest duĔo bardziej czytelne niĔ wywoäanie
assertEquals(calculatedTax, 0.0, 0.0), choè oczywiĈcie wszystko zaleĔy od osobistych
preferencji programisty. Sam uwaĔam wywoäanie w tej formie za bardziej naturalne. Jest krótsze
i nie zmusza nas do podĈwiadomego täumaczenia samego wyraĔenia assertsEquals na zdanie
„no dobrze, zatem wyznaczany podatek musi byè równy zero”. W przypadku pierwszego
wyraĔenia nasz mózg od razu dochodzi do interpretacji: „Ĉwietnie, zakäadamy, Ĕe podatek
bödzie zerowy”, co zajmuje nieporównanie mniej czasu.
Bardziej czytelne testy oznaczajñ teĔ wiökszñ niezawodnoĈè i äatwoĈè w utrzymaniu. JeĈli
interpretacja naszych testów jest prostsza, duĔo äatwiej i szybciej moĔemy stwierdziè, czy
sñ prawidäowe.
WyraĔenie dopasowujñce equalTo (lub is, czyli jego skrócona forma) moĔe byè z powodzeniem
wykorzystywane w roli bardziej czytelnej wersji metody assertEquals:
String result = czerwony ;
assertThat(result, equalTo( czerwony ));
Opisywane wyraĔenia moĔna teĔ äñczyè w bardziej zäoĔone zadania. MoĔemy na przykäad
wykorzystaè wyraĔenie dopasowujñce anyOf do sprawdzenia, czy zmienna color zawiera
äaþcuch czerwony , zielony lub niebieski :
assertThat(color, anyOf(is( czerwony ),is( zielony ),is( niebieski )));
W razie koniecznoĈci moĔemy skojarzyè z naszym testem opis, który dodatkowo uäatwi jego
interpretacjö:
String color = hebanowy ;
assertThat( czarny to czarny , color, is( czarny ));
PowyĔsze wyraĔenie spowoduje wygenerowanie komunikatu o bäödzie uzupeänionego o nasz
opis:
FAILURE!
java.lang.AssertionError: czarny to czarny
Expected: czarny
got: hebanowy
...
MoĔemy teĔ uĔyè intuicyjnego wyraĔenia dopasowujñcego not, które neguje wszystkie pozostaäe
wyraĔenia dopasowujñce:
String color = czarny ;
assertThat(color, is(not(( biaĪy ))));
Te nowe metody w rzeczywistoĈci pochodzñ z zewnötrznej biblioteki nazwanej Hamcrest.
Wachlarz wyraĔeþ dopasowujñcych oferowanych w ramach frameworku JUnit 4.4 jest doĈè
ograniczony. MoĔna jednak ten zbiór uzupeäniè, doäñczajñc do realizowanego projektu bibliotekö
hamcrest-all.jar. Wspomniany interfejs API moĔna pobraè z witryny internetowej biblioteki
Hamcrest2. JeĈli korzystamy z Mavena, moĔemy po prostu dodaè odpowiedniñ referencjö
do pliku POM:
2 Patrz http://code.google.com/p/hamcrest/downloads/list.
10.7. Stosowanie metody assertThat() i biblioteki Hamcrest
_
419
dependency
groupId org.hamcrest /groupId
artifactId hamcrest-all /artifactId
version 1.1 /version
scope test /scope
/dependency
W ten sposób zastöpujemy statyczne wyraĔenie importujñce bibliotekö org.hamcrest.Core
´Matchers wyraĔeniem importujñcym bardziej rozbudowanñ bibliotekö org.hamcrest.
´Matchers. Prezentowane rozwiñzanie daje nam dostöp do znacznie bogatszego zbioru
wyraĔeþ dopasowujñcych. Niektóre z tych dodatkowych wyraĔeþ zostanñ omówione w dal-
szej czöĈci tego podrozdziaäu.
Do najbardziej interesujñcych wyraĔeþ dopasowujñcych naleĔñ mechanizmy upraszczajñce
operacje na kolekcjach. Na przykäad wyraĔenie hasItem moĔna z powodzeniem wykorzystywaè
do przeszukiwania zawartoĈci struktury typu List (w przypadku struktur tablicowych ten sam
efekt moĔna uzyskaè, stosujñc wyraĔenie hasItemInArray):
List String colors = new ArrayList String ();
colors.add( czerwony );
colors.add( zielony );
colors.add( niebieski );
...
assertThat(colors, hasItem( czerwony ));
WyraĔeþ dopasowujñcych hasItem i hasItemInArray moĔna uĔywaè do konstruowania
skomplikowanych testów operujñcych na listach wartoĈci. PoniĔej przedstawiono przykäad
sprawdzania, czy dana lista nie zawiera Ĕadnych elementów:
List Integer ages = new ArrayList Integer ();
ages.add(20);
ages.add(30);
ages.add(40);
...
assertThat(ages, not(hasItem(lessThan(18))));
I odwrotnie, wyraĔenie dopasowujñce isIn umoĔliwia nam sprawdzanie, czy interesujñca nas
lista zawiera konkretny obiekt:
assertThat(20, isIn(ages));
Obsäuga kolekcji nie ogranicza siö tylko do list. WyraĔeþ dopasowujñcych hasKey i hasValue
moĔna uĔywaè do sprawdzania, czy dana mapa (struktura typu Map) zawiera odpowiednio
interesujñcy nas klucz lub wartoĈè:
Map map = new HashMap();
map.put( color , czerwony );
...
assertThat(map, hasValue( czerwony ));
Istnieje nawet wyraĔenie dopasowujñce hasProperty, które umoĔliwia nam testowanie wäa-
ĈciwoĈci obiektów:
Client client = new Client();
client.setClientName( Janina );
...
assertThat(client, hasProperty( clientName , is( Janina )));
W tym podrozdziale dokonaliĈmy przeglñdu zaledwie kilku moĔliwych zastosowaþ tego rodzaju
wyraĔeþ. Inne dostöpne rozwiñzania moĔna znaleĒè w dokumentacji najnowszej wersji tego
API. WyraĔenia dopasowujñce w tej formie umoĔliwiajñ nam tworzenie bardziej czytelnych
420 _
Rozdziaĥ 10. Testowanie kodu z wykorzystaniem frameworku JUnit
i äatwiejszych w utrzymaniu testów, co z kolei stwarza szansö lepszego, szybszego i prostszego
kodowania naszych testów.
10.8. Teorie we frameworku JUnit 4
Innñ nowñ i niezwykle przydatnñ (choè wciñĔ uwaĔanñ za element eksperymentalny) funkcjñ
wprowadzonñ we frameworku 4.4 jest pojöcie teorii (przypuszczenia). Teoria wyraĔa ogólne
przekonanie, które pozostaje prawdziwe dla wielu (byè moĔe nieskoþczenie wielu) zbiorów
danych. Wszelkie ograniczenia zbiorów danych, dla których stosuje siö danñ teoriö, okreĈla
siö mianem zaäoĔeþ.
Programista w pierwszej kolejnoĈci definiuje zbiór punktów danych na potrzeby testów swojej
teorii. Punkt danych jest (z reguäy staäym) elementem danych testowych identyfikowanym
przez adnotacjö @DataPoint. Alternatywnym rozwiñzaniem jest uĔycie zautomatyzowanych
narzödzi analizujñcych nasz kod i automatycznie tworzñcych zbiory danych wzmacniajñcych
lub obalajñcych teoriö. Na przykäad poniĔej definiujemy prawidäowe wartoĈci dla lat 2007
i 2008:
@DataPoint public static int YEAR_2007 = 2007;
@DataPoint public static int YEAR_2008 = 2008;
MoĔemy teraz uĔyè innego zbioru danych do zdefiniowania danych testowych wykorzysty-
wanych w roli potencjalnych dochodów podatników:
@DataPoint public static double INCOME_1 = 0.0;
@DataPoint public static double INCOME_2 = 0.01;
@DataPoint public static double INCOME_3 = 100.0;
@DataPoint public static double INCOME_4 = 13999.99;
@DataPoint public static double INCOME_5 = 14000.0;
Aby zdefiniowaè test wykorzystujñcy teoriö, naleĔy w miejsce standardowej adnotacji @Test
uĔyè adnotacji @Theory. Teoria jest zwykäñ metodñ otrzymujñcñ na wejĈciu pewnñ liczbö
parametrów. Framework sam okreĈla, których punktów danych naleĔy uĔyè dla poszczególnych
parametrów naszych metod testowych, na podstawie ich typów. KaĔdy punkt danych jest
przekazywany za poĈrednictwem kaĔdego parametru tego samego typu. Takie rozwiñzanie
stwarza pewne problemy, jeĈli stosujemy wiele parametrów tego samego typu. Jak siö za chwilö
przekonamy, do ograniczania moĔliwych wartoĈci przypisywanych poszczególnym parametrom
säuĔñ tzw. zaäoĔenia.
Kolejnym krokiem jest zdefiniowanie wspomnianych zaäoĔeþ za pomocñ adnotacji @assumeThat.
Stosujñc zaäoĔenia w ramach przypadku testowego wykorzystujñcego teoriö, moĔemy äatwo
ograniczyè dane testowe, które bödñ uĔywane podczas wykonywania tego przypadku testowego.
W poniĔszym przykäadzie ograniczamy zakres testów naszego przypadku do roku 2007
i dochodów z przedziaäu od 0 do 14 tys. zäotych:
assumeThat(year, is(2007));
oraz
assumeThat(income, both(greaterThan(0.00)).and(lessThan(14000.00)));
Moduä rozszerzenia JUnitRunner wykonuje dany test dla wszystkich moĔliwych kombinacji
punktów danych zgodnych z zaäoĔeniami, czyli w tym przypadku dla kombinacji staäej
YEAR_2007 i staäych INCOME_2, INCOME_3 oraz INCOME_4:
10.8. Teorie we frameworku JUnit 4
_
421
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.junit.Assume.assumeThat;
import java.math.BigDecimal;
import org.junit.experimental.theories.DataPoint;
import org.junit.experimental.theories.Theories;
import org.junit.experimental.theories.Theory;
import org.junit.runner.RunWith;
@RunWith(Theories.class)
public class TaxCalculatorTheoryTest {
@DataPoint public static int YEAR_2007 = 2007;
@DataPoint public static int YEAR_2008 = 2008;
@DataPoint public static BigDecimal INCOME_1 = new BigDecimal(0.0);
@DataPoint public static double INCOME_2 = 0.01;
@DataPoint public static double INCOME_3 = 100.0;
@DataPoint public static double INCOME_4 = 13999.99;
@DataPoint public static double INCOME_5 = 14000.0;
@SuppressWarnings( unchecked )
@Theory
public void lowTaxRateIsNineteenPercent(int year, double income) {
assumeThat(year, is(2007));
assumeThat(income, allOf(greaterThan(0.00),lessThan(14000.00)));
TaxCalculator calculator = getTaxCalculator();
double calculatedTax = calculator.calculateIncomeTax(year, income);
double expectedIncome = calculatedTax * 1000/195;
assertThat(expectedIncome, closeTo(income,0.001));
System.out.println( Rok: + year + , Dochód: + income + , Podatek:
+ calculatedTax);
}
private TaxCalculator getTaxCalculator() {
return new TaxCalculatorImpl();
}
}
W wyniku wykonania tego kodu otrzymamy nastöpujñce dane:
Rok: 2007, Dochód: 0.01, Podatek: 0.0019500000000000001
Rok: 2007, Dochód: 100.0, Podatek: 19.5
Rok: 2007, Dochód: 13999.99, Podatek: 2729.99805
Dla uproszczenia wykorzystujemy wartoĈci typu double. W prawdziwej aplikacji biznesowej
prawdopodobnie naleĔaäoby uĔyè typu gwarantujñcego wiökszñ precyzjö operacji na danych
pieniöĔnych, czyli typu BigDecimal lub dedykowanej klasy Money.
W razie niepowodzenia tego testu zostanie wyĈwietlony opisowy komunikat obejmujñcy
szczegóäy punktów danych, które doprowadziäy do bäödu:
org.junit.experimental.theories.internal.ParameterizedAssertionError:
lowTaxRateIsNineteenPercent(2007, 0.01)
Caused by: java.lang.AssertionError:
Expected: is 0.01
Got: is 0.0
MoĔemy teraz dodaè do tego testu inne teorie, aby zweryfikowaè inne podzbiory naszych
danych testowych. MoĔliwy zbiór punktów danych (po zastosowaniu zaäoĔeþ) jest stosowany
osobno dla kaĔdej takiej teorii.
422
_
Rozdziaĥ 10. Testowanie kodu z wykorzystaniem frameworku JUnit
10.9. Stosowanie frameworku JUnit 4
w projektach Mavena 2
Maven 2 do wykonywania testów jednostkowych wykorzystuje moduä rozszerzenia Surefire
(patrz podrozdziaä 2.13). Moduä rozszerzenia obsäuguje testy jednostkowe zarówno frameworku
JUnit 3, jak i frameworku JUnit 4 — klasy testów muszñ siö znajdowaè w katalogu test, a Maven
automatycznie je wykrywa i uruchamia. MoĔna nawet äñczyè testy frameworków JUnit 3
i JUnit 4 w ramach tej samej aplikacji. Testy jednostkowe wykonujemy dokäadnie tak samo jak
pozostaäe testy Mavena, czyli za pomocñ polecenia mvn test:
$ mvn test
[INFO] Scanning for project
Pobierz darmowy fragment (pdf)