Date post: | 25-May-2015 |
Category: |
Documents |
Upload: | roman-pichlik |
View: | 604 times |
Download: | 0 times |
Spring frameworkMotto: 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.
1Sunday 13 May 2012
Spring frameworkMotto: Musíte rozbít vejce když chcete udělat omeletu
2Sunday 13 May 2012
3Sunday 13 May 2012
Spring TDDTestování aplikací postavených na Spring frameworku
4Sunday 13 May 2012
Proč testujeme
5Sunday 13 May 2012
Primární Motivace
• Pocit sucha a bezpečí
• Verifikace kódu, že opravdu funguje
• Zpětná vazba při změnách
6Sunday 13 May 2012
klidné spaní
Jak testujeme
7Sunday 13 May 2012
Manuální testy
• Historicky běžná součást vývojového procesu
• Testovací fáze
• Vývojáři nebo QA oddělení
8Sunday 13 May 2012
Hlavní rysy
• Pomalé
• Drahé
• Neefektivní
• Náchylné k chybě lidského faktoru
9Sunday 13 May 2012
Pomalé - trvání testovacího kolečka, specifikace, vlastní průchod testuDrahé - 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)
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
10Sunday 13 May 2012
RC= Go nebo no Go nebo Hotfix díky tomu, že nám hoří termínNeškáluje = nový tester neznamená větší otestovanost (roste i code base)
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é11Sunday 13 May 2012
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
12Sunday 13 May 2012
Rychlejší release cyklus díky testům závisí na tom jak drahé je pro nás testy psát a udržovat
Manuální vs Automatické testy
13Sunday 13 May 2012
Kolik stojí opravení chybyN
ákla
dy n
a od
stra
nění
chy
by
čas nalezení chyby
14Sunday 13 May 2012
Náklady na odstranění rostou exponenciálně s čase objevení chyby
Kolik stojí opravení chybyN
ákla
dy n
a od
stra
nění
chy
by
čas nalezení chyby
automatické testy manuální testy15Sunday 13 May 2012
Náklady na odstranění rostou exponenciálně s čase objevení chybyAutomatické testy snižují čas na odhalení chyby
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ávrhu16Sunday 13 May 2012
Automatické testy
17Sunday 13 May 2012
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
18Sunday 13 May 2012
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ář
19Sunday 13 May 2012
JDK se považuje za důveryhodné => nemusíme dělat stuby
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; }}
20Sunday 13 May 2012
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; }}
Externí třída (v testu nahradit stub/mock)
20Sunday 13 May 2012
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; }}
Externí třída (v testu nahradit stub/mock)
dvě testovací metody (scénáře)20Sunday 13 May 2012
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; }}
Externí třída (v testu nahradit stub/mock)
dvě testovací metody (scénáře)20Sunday 13 May 2012
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; }}
Externí třída (v testu nahradit stub/mock)
dvě testovací metody (scénáře)20Sunday 13 May 2012
Stubpublic class BookStoreDaoStub implements BookStoreDao{
private Book book;
public Book getBook(Long bookId) { if(book != null && bookId.equals(book.getId())) { return book; } return null; }
public void saveBook(Book book) { this.book = book; }
public Book getBook() { return book; }
public void setBook(Book book) { this.book = book; }}
Implementuje stejné rozhraní
jednoduché chování připravené pro test
Možnost verifikovat stav stubu
21Sunday 13 May 2012
Použití stubupublic class ReservationServiceImplTest {
private BookStoreDao bookStoreDao; private ReservationServiceImpl reservationServiceImpl = new ReservationServiceImpl(); @Before public void setup(){ bookStoreDao = new BookStoreDaoStub(); reservationServiceImpl.setBookStoreDao(bookStoreDao); }
@Test public void testReserveNonExistingBook() { try { reservationServiceImpl.reserveBook(-1l); fail("BookNotFoundException musi byt vyhozena pro neexistujici knihu"); } catch(BookNotFoundException e) { //expected } }
}
Příprava stubu
22Sunday 13 May 2012
Použití stubu
• Výhody
• Znovupoužitelný kód
• Test support modul
• Nevýhody
• Změna interface znamená změnu stubu
• Implementace všech metod23Sunday 13 May 2012
žádné smart defaults
Použití mocku
• Mock je automatický generovaná třía
• Popisujeme chování, které nás zajímá
• Můžeme zkontrolovat interakci
24Sunday 13 May 2012
Mockovací knihovná Mockito
• Velmi pohodlné mockování
• Fluent API
• Jednoduchá na použití
• Umožňuje verifikovat stav mocku po testu
25Sunday 13 May 2012
jsou i další mock knihovny
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() { try { reservationServiceImpl.reserveBook(-1l); fail("BookNotFoundException musi byt vyhozena pro neexistujici knihu"); } catch(BookNotFoundException e) { //expected } }
Příprava mocku
26Sunday 13 May 2012
Mock vs. Stub
• Mock
• Smart defaults
• Pokud se jedná o složitější rozhraní
• Stub
• Znovupoužitelné
27Sunday 13 May 2012
Integrační testy se Springem
28Sunday 13 May 2012
Spring test• spring-test modul
• Umožňuje nainicializovat Spring
• Umožňuje nainjectovat testované beany do testu
• Centrální třídy
• SpringJUnit4ClassRunner
• @ContextConfiguration29Sunday 13 May 2012
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;
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:META-INF/applicationContext.xml")public class ReservationServiceImplTest {
@Autowired private ReservationService reservationService;
@Test public void testReserveNonExistingBook() { try { reservationService.reserveBook(-1l); fail("BookNotFoundException musi byt vyhozena pro neexistujici knihu"); } catch(BookNotFoundException e) { //expected } }}
Integrace Spring a JUnit
Konfigurace Springu
Nainjectování testované beany
30Sunday 13 May 2012
• 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
31Sunday 13 May 2012