SlideShare a Scribd company logo
1 of 35
Download to read offline
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
Spring framework
                     Motto: Musíte rozbít vejce když chcete udělat omeletu




Sunday 13 May 2012                                                           2
Sunday 13 May 2012   3
Spring TDD
                     Testování aplikací postavených na Spring frameworku




Sunday 13 May 2012                                                         4
Proč testujeme




Sunday 13 May 2012                    5
Primární Motivace


                     • Pocit sucha a bezpečí
                      • Verifikace kódu, že opravdu
                        funguje
                      • Zpětná vazba při změnách



Sunday 13 May 2012                                   6

klidné spaní
Jak testujeme




Sunday 13 May 2012                   7
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
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)
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)
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
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
Manuální vs Automatické testy




Sunday 13 May 2012                   13
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
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
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
Automatické testy




Sunday 13 May 2012                       17
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
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
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
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
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
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
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
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
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
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
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
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
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
Mock vs. Stub
                     • Mock
                      • Smart defaults
                      • Pokud se jedná o složitější
                        rozhraní
                     • Stub
                      • Znovupoužitelné

Sunday 13 May 2012                                    27
Integrační testy se Springem




Sunday 13 May 2012                       28
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
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
• 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

More Related Content

More from Roman Pichlík

App Design Architecture
App Design ArchitectureApp Design Architecture
App Design ArchitectureRoman Pichlík
 
MongoDB for Java Developers
MongoDB for Java DevelopersMongoDB for Java Developers
MongoDB for Java DevelopersRoman Pichlík
 
Nosql from java developer pov
Nosql from java developer povNosql from java developer pov
Nosql from java developer povRoman Pichlík
 
Spring framework - J2EE S Lidskou Tvari
Spring framework - J2EE S Lidskou TvariSpring framework - J2EE S Lidskou Tvari
Spring framework - J2EE S Lidskou TvariRoman Pichlík
 
Dependency Injection Frameworky
Dependency Injection FrameworkyDependency Injection Frameworky
Dependency Injection FrameworkyRoman Pichlík
 

More from Roman Pichlík (8)

App Design Architecture
App Design ArchitectureApp Design Architecture
App Design Architecture
 
Spring MVC
Spring MVCSpring MVC
Spring MVC
 
Spring integration
Spring integrationSpring integration
Spring integration
 
Spring Web Services
Spring Web ServicesSpring Web Services
Spring Web Services
 
MongoDB for Java Developers
MongoDB for Java DevelopersMongoDB for Java Developers
MongoDB for Java Developers
 
Nosql from java developer pov
Nosql from java developer povNosql from java developer pov
Nosql from java developer pov
 
Spring framework - J2EE S Lidskou Tvari
Spring framework - J2EE S Lidskou TvariSpring framework - J2EE S Lidskou Tvari
Spring framework - J2EE S Lidskou Tvari
 
Dependency Injection Frameworky
Dependency Injection FrameworkyDependency Injection Frameworky
Dependency Injection Frameworky
 

Spring Testing

  • 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
  • 3. Sunday 13 May 2012 3
  • 4. Spring TDD Testování aplikací postavených na Spring frameworku Sunday 13 May 2012 4
  • 6. Primární Motivace • Pocit sucha a bezpečí • Verifikace kódu, že opravdu funguje • Zpětná vazba při změnách Sunday 13 May 2012 6 klidné spaní
  • 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
  • 13. Manuální vs Automatické testy Sunday 13 May 2012 13
  • 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
  • 32. Integrační testy se Springem Sunday 13 May 2012 28
  • 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