1. Spring framework
Motto: Musíte rozbít vejce když chcete udělat omeletu
Spring framework training materials by Roman Pichlík is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
Sunday 13 May 2012 1
2. Spring framework
Motto: Musíte rozbít vejce když chcete udělat omeletu
Sunday 13 May 2012 2
8. Manuální testy
• Historicky běžná součást
vývojového procesu
• Testovací fáze
• Vývojáři nebo QA oddělení
Sunday 13 May 2012 8
9. Hlavní rysy
• Pomalé
• Drahé
• Neefektivní
• Náchylné k chybě lidského faktoru
Sunday 13 May 2012 9
Pomalé - trvání testovacího kolečka, specifikace, vlastní průchod testu
Drahé - lidský čas je oproti strojovému stále dražší (i v Bengalore)
Neefektivní - otestování low level změny je kolikrát nemožné
Lidský faktor - člověk je tvor líny, monotóní práce je ubijející (ne pro stroj)
10. Dopady manuálního testování
• Delší release cyklus
• Chyby se odhalí na konci
vývojového cyklu
• Problém chyba v RC
• Neškáluje
Sunday 13 May 2012 10
RC= Go nebo no Go nebo Hotfix díky tomu, že nám hoří termín
Neškáluje = nový tester neznamená větší otestovanost (roste i code base)
11. Automatické testy
• Píší se společně s kódem
• Kontinuální evoluce
• Různé testy podle úrovně
abstrakce a cílové oblasti
• Jednotkové
• Integrační
• Výkonové
Sunday 13 May 2012 11
12. Dopady aut. testů
• Rychlejší release cyklus
• Test coverage
• Známe slabá místa
• Umožňují lépe pochopit fungování
kódu
• Ukazují špatný/dobrý design
Sunday 13 May 2012 12
Rychlejší release cyklus díky testům závisí na tom jak drahé je pro nás testy psát a udržovat
14. Kolik stojí opravení chyby
Náklady na odstranění chyby
čas nalezení chyby
Sunday 13 May 2012 14
Náklady na odstranění rostou exponenciálně s čase objevení chyby
15. Kolik stojí opravení chyby
Náklady na odstranění chyby
čas nalezení chyby
automatické testy manuální testy
Sunday 13 May 2012 15
Náklady na odstranění rostou exponenciálně s čase objevení chyby
Automatické testy snižují čas na odhalení chyby
16. Doporučení
• Zaměřte se na automatické testy
• Testy lze zavádět inkrementálně
• Nový kód vždy
• Starý kód pokud se do něj šahá
• Starý kód podle důležitosti
• Testy jsou zrcadlem návrhu
Sunday 13 May 2012 16
18. Jednotkové vs. Integrační
• Jednotkové testy
• Konkrétní třída v izolaci
• Žádné závislosti
• Odstíněné od prostředí
• Integrační testy
• Interakce několika komponent
Sunday 13 May 2012 18
19. Jednotkové testy
• Nejdůležitější je izolace
• Pokud možno všechny ostatní
třídy odizolované
• Použití Stub a Mock objektů
• Nemíchat testovací scénáře
• Jedna testovací metoda per
scénář
Sunday 13 May 2012 19
JDK se považuje za důveryhodné => nemusíme dělat stuby
20. Unit test
public class ReservationServiceImpl implements ReservationService{
private BookStoreDao bookStoreDao;
private AtomicLong counter = new AtomicLong();
private Map<Long, Reservation> resevations = new HashMap<Long, Reservation>();
public Reservation reserveBook(Long bookId) {
Book book = bookStoreDao.getBook(bookId);
if(book == null) {
throw new BookNotFoundException(bookId);
}
ReservationImpl reservationImpl = new ReservationImpl();
reservationImpl.setReservationId(counter.incrementAndGet());
reservationImpl.setBookId(bookId);
return reservationImpl;
}
}
Sunday 13 May 2012 20
21. Unit test
Externí třída (v testu nahradit stub/mock)
public class ReservationServiceImpl implements ReservationService{
private BookStoreDao bookStoreDao;
private AtomicLong counter = new AtomicLong();
private Map<Long, Reservation> resevations = new HashMap<Long, Reservation>();
public Reservation reserveBook(Long bookId) {
Book book = bookStoreDao.getBook(bookId);
if(book == null) {
throw new BookNotFoundException(bookId);
}
ReservationImpl reservationImpl = new ReservationImpl();
reservationImpl.setReservationId(counter.incrementAndGet());
reservationImpl.setBookId(bookId);
return reservationImpl;
}
}
Sunday 13 May 2012 20
22. Unit test
Externí třída (v testu nahradit stub/mock)
public class ReservationServiceImpl implements ReservationService{
private BookStoreDao bookStoreDao;
private AtomicLong counter = new AtomicLong();
private Map<Long, Reservation> resevations = new HashMap<Long, Reservation>();
public Reservation reserveBook(Long bookId) {
Book book = bookStoreDao.getBook(bookId);
if(book == null) {
throw new BookNotFoundException(bookId);
}
ReservationImpl reservationImpl = new ReservationImpl();
reservationImpl.setReservationId(counter.incrementAndGet());
reservationImpl.setBookId(bookId);
return reservationImpl;
}
}
dvě testovací metody (scénáře)
Sunday 13 May 2012 20
23. Unit test
Externí třída (v testu nahradit stub/mock)
public class ReservationServiceImpl implements ReservationService{
private BookStoreDao bookStoreDao;
private AtomicLong counter = new AtomicLong();
private Map<Long, Reservation> resevations = new HashMap<Long, Reservation>();
public Reservation reserveBook(Long bookId) {
Book book = bookStoreDao.getBook(bookId);
if(book == null) {
throw new BookNotFoundException(bookId);
}
ReservationImpl reservationImpl = new ReservationImpl();
reservationImpl.setReservationId(counter.incrementAndGet());
reservationImpl.setBookId(bookId);
return reservationImpl;
}
}
dvě testovací metody (scénáře)
Sunday 13 May 2012 20
24. Unit test
Externí třída (v testu nahradit stub/mock)
public class ReservationServiceImpl implements ReservationService{
private BookStoreDao bookStoreDao;
private AtomicLong counter = new AtomicLong();
private Map<Long, Reservation> resevations = new HashMap<Long, Reservation>();
public Reservation reserveBook(Long bookId) {
Book book = bookStoreDao.getBook(bookId);
if(book == null) {
throw new BookNotFoundException(bookId);
}
ReservationImpl reservationImpl = new ReservationImpl();
reservationImpl.setReservationId(counter.incrementAndGet());
reservationImpl.setBookId(bookId);
return reservationImpl;
}
}
dvě testovací metody (scénáře)
Sunday 13 May 2012 20
25. Stub
public class BookStoreDaoStub implements BookStoreDao{
private Book book;
Implementuje stejné rozhraní
public Book getBook(Long bookId) {
if(book != null && bookId.equals(book.getId())) {
return book;
}
return null;
jednoduché chování připravené pro test
}
public void saveBook(Book book) {
this.book = book;
}
public Book getBook() {
return book;
} Možnost verifikovat stav stubu
public void setBook(Book book) {
this.book = book;
}
}
Sunday 13 May 2012 21
26. Použití stubu
public class ReservationServiceImplTest {
private BookStoreDao bookStoreDao;
private ReservationServiceImpl reservationServiceImpl = new ReservationServiceImpl();
@Before
public void setup(){
bookStoreDao = new BookStoreDaoStub();
reservationServiceImpl.setBookStoreDao(bookStoreDao);
}
@Test
public void testReserveNonExistingBook() { Příprava stubu
try {
reservationServiceImpl.reserveBook(-1l);
fail("BookNotFoundException musi byt vyhozena pro neexistujici knihu");
} catch(BookNotFoundException e) {
//expected
}
}
}
Sunday 13 May 2012 22
27. Použití stubu
• Výhody
• Znovupoužitelný kód
• Test support modul
• Nevýhody
• Změna interface znamená změnu
stubu
• Implementace všech metod
Sunday 13 May 2012 23
žádné smart defaults
28. Použití mocku
• Mock je automatický generovaná
třía
• Popisujeme chování, které nás
zajímá
• Můžeme zkontrolovat interakci
Sunday 13 May 2012 24
29. Mockovací knihovná Mockito
• Velmi pohodlné mockování
• Fluent API
• Jednoduchá na použití
• Umožňuje verifikovat stav mocku
po testu
Sunday 13 May 2012 25
jsou i další mock knihovny
30. Mock s Mockitem
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class ReservationServiceImplTest {
private BookStoreDao bookStoreDao;
private ReservationServiceImpl reservationServiceImpl = new ReservationServiceImpl();
@Before
public void setup(){
bookStoreDao = mock(BookStoreDao.class);
when(bookStoreDao.getBook(-1l)).thenReturn(null);
reservationServiceImpl.setBookStoreDao(bookStoreDao);
}
@Test
public void testReserveNonExistingBook() {
Příprava mocku
try {
reservationServiceImpl.reserveBook(-1l);
fail("BookNotFoundException musi byt vyhozena pro neexistujici knihu");
} catch(BookNotFoundException e) {
//expected
}
}
Sunday 13 May 2012 26
31. Mock vs. Stub
• Mock
• Smart defaults
• Pokud se jedná o složitější
rozhraní
• Stub
• Znovupoužitelné
Sunday 13 May 2012 27
33. Spring test
• spring-test modul
• Umožňuje nainicializovat Spring
• Umožňuje nainjectovat testované
beany do testu
• Centrální třídy
• SpringJUnit4ClassRunner
• @ContextConfiguration
Sunday 13 May 2012 29
34. import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
Integrace Spring a JUnit
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:META-INF/applicationContext.xml")
public class ReservationServiceImplTest {
@Autowired Konfigurace Springu
private ReservationService reservationService;
Nainjectování testované
@Test
public void testReserveNonExistingBook() { beany
try {
reservationService.reserveBook(-1l);
fail("BookNotFoundException musi byt vyhozena pro neexistujici knihu");
} catch(BookNotFoundException e) {
//expected
}
}
}
Sunday 13 May 2012 30
35. • Napište jednotkový test pro ReservationServiceImp
• použijte mock pro BookStoreDao
• Napište integrační test pro ReservationServiceImp za
pomocí Springu
• Jako BookStoreDao nedefinujte beanu, která bude
naimplementovaná jako stub
Sunday 13 May 2012 31