O slideshow foi denunciado.
Utilizamos seu perfil e dados de atividades no LinkedIn para personalizar e exibir anúncios mais relevantes. Altere suas preferências de anúncios quando desejar.
Unit testing unitils - dbmaintain Filip Neven
Presentation goal Demonstrate the added value Unitils can give to your projects
Unitils ‘Mission statement’ <ul><li>Provide a good testing environment
Remove boilerplate code
Automate stuff where possible
Help applying best practices </li></ul>
Why Unitils? <ul><li>Tackle complexity of persistence layer testing </li></ul><ul><ul><li>Many practical problems
A lot of boilerplate code required </li></ul></ul><ul><li>Offer all kinds of useful functionalities </li></ul><ul><ul><li>...
Mock objects </li></ul></ul>
Agenda <ul><li>History
Features by example </li></ul><ul><ul><li>Persistence layer testing
Reflection assert
Database maintenance
Mock objects </li></ul></ul><ul><li>Unitils design
Roadmap & summary </li></ul>
Introduction <ul><li>Originates from Ordina Testing & QA task force (2005) </li></ul><ul><ul><li>Brainstorm
Testing guidelines:  www.unitils.org/guidelines.html
Supporting code </li></ul></ul>   Unitils open source project
Features <ul><li>Persistence layer testing </li></ul><ul><ul><li>JPA
Hibernate </li></ul></ul><ul><li>Automatic database maintenance </li></ul><ul><ul><li>DbMaintain </li></ul></ul><ul><li>Ge...
Mock objects </li></ul>
Persistence layer testing <ul><li>Important to test persistence layer </li></ul><ul><ul><li>Queries are often complex
Two separated parts -> mismatches more likely </li></ul></ul><ul><li>Testing persistence is difficult </li></ul><ul><ul><l...
Provide test data </li></ul></ul><ul><li>Lot of boilerplate code required </li></ul><ul><ul><li>Depends on technology: Pla...
Persistence layer testing guidelines <ul><li>Need control over database & test data </li></ul><ul><ul><li>Test database
Empty database
Small dataset per group of related tests </li></ul></ul><ul><ul><ul><li>Typically one dataset per test class </li></ul></u...
Separate developer schema’s <ul><li>Separate schema per developer </li></ul><ul><ul><li>Develop in isolation
Test in isolation </li></ul></ul>
Persistence layer testing – DAO example public class UserDao { @PersistenceContext private EntityManager entityManager; pu...
Persistence layer testing – test example @DataSet @JpaEntityManagerFactory (persistenceUnit=“eshop”,  configFiles={“persis...
Loading test data - example @DataSet @JpaEntityManagerFactory(persistenceUnit=“eshop”,  configFiles={“persistence-test.xml...
Loading test data <ul><li>@DataSet </li></ul><ul><ul><li>Dbunit dataset is loaded before each test </li></ul></ul><ul><ul>...
Loading test data - possibilities <ul><li>Custom file name </li></ul><ul><li>Method - specific data set </li></ul><ul><li>...
Loading test data - XSD <ul><li>XSD for validation & auto completion </li></ul><ul><ul><li>Automatically generated by Unit...
Loading test data – multi-schema support <ul><li>Multi – schema dataset support </li></ul><?xml version='1.0' encoding='UT...
Loading test data – dbunit issues <ul><li>Solve annoying dbunit issue </li></ul>With Unitils: <?xml version='1.0' encoding...
Verify database contents <ul><li>@ExpectedDataSet </li></ul><ul><ul><li>Verify database contents after test execution </li...
Transaction support <ul><li>Run each test in a transaction </li></ul><ul><ul><li>Avoid problems with ‘select for update’ o...
Required in some environments </li></ul></ul><ul><li>Possible to rollback after each test </li></ul><ul><ul><li>Facilitate...
Enables using pre-filled test DB </li></ul></ul><ul><li>Default behavior: commit after every test </li></ul><ul><ul><li>Mo...
Transaction support - example @DataSet @Transactional(TransactionMode.ROLLBACK) @JpaEntityManagerFactory(persistenceUnit=“...
JPA integration - example @DataSet @JpaEntityManagerFactory(persistenceUnit=“eshop”,  configFiles={“persistence-test.xml”}...
JPA integration <ul><li>@JpaEntityManagerFactory </li></ul><ul><ul><li>Create EntityManagerFactory
Connects with unit test database
New EntityManager for each test </li></ul></ul><ul><ul><ul><li>Attached to unitils transaction </li></ul></ul></ul><ul><ul...
JPA integration – persistence providers <ul><li>Supported persistence providers </li></ul><ul><ul><li>Hibernate
Toplink
OpenJPA </li></ul></ul>
JPA integration – mapping test <ul><li>Entity / database mapping test </li></ul><ul><ul><li>Verifies if database structure...
Only works when persistence provider = hibernate </li></ul></ul>@Test public void testMappingToDatabase() { JpaUnitils.ass...
Reflection assert - example @DataSet @JpaEntityManagerFactory(persistenceUnit=“eshop”,  configFiles={“persistence-test.xml...
Reflection assert <ul><li>ReflectionAssert </li></ul>assertReflectionEquals(expectedUser, actualUser); <ul><ul><li>Compare...
Recursively compares inner objects
Loops over collections and arrays
Reports all differences </li></ul></ul>
Reflection assert - leniency <ul><li>Leniency </li></ul><ul><ul><li>Keep your tests maintainable
Only verify what’s relevant for the test </li></ul></ul><ul><li>Lenient by default:  </li></ul><ul><ul><li>Lenient number ...
Lenient collection types </li></ul></ul><ul><li>Leniency options:  assertLenientEquals ( ... ) </li></ul><ul><ul><li>Lenie...
Ignore java default values (0 or null) </li></ul></ul>
Reflection assert – lenient collection order <ul><li>Ignore order of collections and arrays </li></ul>assertReflectionEqua...
Reflection assert – ignore defaults <ul><li>Ignore java default values: 0 or null </li></ul>assertReflectionEquals(expecte...
Reflection assert – check property value <ul><li>Check property value </li></ul>assertPropertyLenientEquals( &quot; addres...
Persistence layer testing - example @DataSet @JpaEntityManagerFactory (persistenceUnit=“eshop”,  configFiles={“persistence...
Base test class with all plumbing @DataSet @JpaEntityManagerFactory (persistenceUnit=“eshop”,  configFiles={“persistence-t...
Test without plumbing public class UserDaoTest extends BaseDaoTest { UserDao userDao = new UserDao(); @Override protected ...
Hibernate support - example @DataSet public class UserDaoTest extends UnitilsJUnit4 { @HibernateSessionFactory(“hibernate-...
Spring integration – DAO example import org.springframework.orm.hibernate3.support.HibernateDaoSupport; public class UserD...
Spring integration – test example @SpringApplicationContext({“eshop-config.xml”, “test-config.xml”}) @DataSet public class...
Spring integration - configuration eshop-config.xml <bean id=&quot;userDao&quot; class=&quot;eshop.dao.UserDao&quot;> <pro...
Spring integration <ul><li>@SpringApplicationContext </li></ul><ul><ul><li>Application context is loaded
Typically application & test specific config file </li></ul></ul><ul><li>@SpringBean </li></ul><ul><ul><li>Inject bean fro...
Other possibilities </li></ul></ul><ul><ul><ul><li>@SpringBeanByName, @SpringBeanByType </li></ul></ul></ul>
Automatic database maintenance <ul><li>Automatic database maintenance </li></ul><ul><ul><li>Currently still part of unitil...
Split off into DbMaintain project </li></ul></ul><ul><ul><ul><li>1.0 released in february </li></ul></ul></ul><ul><ul><li>...
Why automatic database maintenance? <ul><li>Drawbacks of manual maintenance </li></ul><ul><ul><li>Lot of databases – lot t...
What was rolled out where? </li></ul></ul>   Time consuming, error prone
Why automatic database maintenance? <ul><li>Fully automatic deployments </li></ul><ul><ul><li>Enables frequent deployments
Tester / customer can trigger deployment </li></ul></ul><ul><ul><ul><li>Shorter feedback cycle </li></ul></ul></ul><ul><ul...
Database maintainer – basic usage <ul><ul><li>Folder with indexed scripts </li></ul></ul><ul><ul><li>Database table stores...
Database maintainer – script organization <ul><li>Work incremental </li></ul><ul><ul><li>Database change = new script
Próximos SlideShares
Carregando em…5
×

Unit testing: unitils & dbmaintain

8.943 visualizações

Publicada em

Publicada em: Tecnologia
  • DOWNLOAD FULL BOOKS, INTO AVAILABLE FORMAT ......................................................................................................................... ......................................................................................................................... 1.DOWNLOAD FULL. PDF EBOOK here { https://tinyurl.com/y3nhqquc } ......................................................................................................................... 1.DOWNLOAD FULL. EPUB Ebook here { https://tinyurl.com/y3nhqquc } ......................................................................................................................... 1.DOWNLOAD FULL. doc Ebook here { https://tinyurl.com/y3nhqquc } ......................................................................................................................... 1.DOWNLOAD FULL. PDF EBOOK here { https://tinyurl.com/y3nhqquc } ......................................................................................................................... 1.DOWNLOAD FULL. EPUB Ebook here { https://tinyurl.com/y3nhqquc } ......................................................................................................................... 1.DOWNLOAD FULL. doc Ebook here { https://tinyurl.com/y3nhqquc } ......................................................................................................................... ......................................................................................................................... ......................................................................................................................... .............. Browse by Genre Available eBooks ......................................................................................................................... Art, Biography, Business, Chick Lit, Children's, Christian, Classics, Comics, Contemporary, Cookbooks, Crime, Ebooks, Fantasy, Fiction, Graphic Novels, Historical Fiction, History, Horror, Humor And Comedy, Manga, Memoir, Music, Mystery, Non Fiction, Paranormal, Philosophy, Poetry, Psychology, Religion, Romance, Science, Science Fiction, Self Help, Suspense, Spirituality, Sports, Thriller, Travel, Young Adult,
       Responder 
    Tem certeza que deseja  Sim  Não
    Insira sua mensagem aqui

Unit testing: unitils & dbmaintain

  1. 1. Unit testing unitils - dbmaintain Filip Neven
  2. 2. Presentation goal Demonstrate the added value Unitils can give to your projects
  3. 3. Unitils ‘Mission statement’ <ul><li>Provide a good testing environment
  4. 4. Remove boilerplate code
  5. 5. Automate stuff where possible
  6. 6. Help applying best practices </li></ul>
  7. 7. Why Unitils? <ul><li>Tackle complexity of persistence layer testing </li></ul><ul><ul><li>Many practical problems
  8. 8. A lot of boilerplate code required </li></ul></ul><ul><li>Offer all kinds of useful functionalities </li></ul><ul><ul><li>Assertion using reflection
  9. 9. Mock objects </li></ul></ul>
  10. 10. Agenda <ul><li>History
  11. 11. Features by example </li></ul><ul><ul><li>Persistence layer testing
  12. 12. Reflection assert
  13. 13. Database maintenance
  14. 14. Mock objects </li></ul></ul><ul><li>Unitils design
  15. 15. Roadmap & summary </li></ul>
  16. 16. Introduction <ul><li>Originates from Ordina Testing & QA task force (2005) </li></ul><ul><ul><li>Brainstorm
  17. 17. Testing guidelines: www.unitils.org/guidelines.html
  18. 18. Supporting code </li></ul></ul> Unitils open source project
  19. 19. Features <ul><li>Persistence layer testing </li></ul><ul><ul><li>JPA
  20. 20. Hibernate </li></ul></ul><ul><li>Automatic database maintenance </li></ul><ul><ul><li>DbMaintain </li></ul></ul><ul><li>General testing utilities </li></ul><ul><ul><li>Reflection assert </li></ul></ul><ul><li>Spring integration
  21. 21. Mock objects </li></ul>
  22. 22. Persistence layer testing <ul><li>Important to test persistence layer </li></ul><ul><ul><li>Queries are often complex
  23. 23. Two separated parts -> mismatches more likely </li></ul></ul><ul><li>Testing persistence is difficult </li></ul><ul><ul><li>Test database
  24. 24. Provide test data </li></ul></ul><ul><li>Lot of boilerplate code required </li></ul><ul><ul><li>Depends on technology: Plain old JDBC, ORM, spring </li></ul></ul>
  25. 25. Persistence layer testing guidelines <ul><li>Need control over database & test data </li></ul><ul><ul><li>Test database
  26. 26. Empty database
  27. 27. Small dataset per group of related tests </li></ul></ul><ul><ul><ul><li>Typically one dataset per test class </li></ul></ul></ul>
  28. 28. Separate developer schema’s <ul><li>Separate schema per developer </li></ul><ul><ul><li>Develop in isolation
  29. 29. Test in isolation </li></ul></ul>
  30. 30. Persistence layer testing – DAO example public class UserDao { @PersistenceContext private EntityManager entityManager; public List<User> findByLastName(String lastName) { return entityManager.createQuery( “ select u from User u where u.lastName = :lastName”) .setParameter(“lastName”, lastName) .getResultList(); } // ... }
  31. 31. Persistence layer testing – test example @DataSet @JpaEntityManagerFactory (persistenceUnit=“eshop”, configFiles={“persistence-test.xml”}) public class UserDaoTest extends UnitilsJUnit4 { @PersistenceContext EntityManager entityManager; UserDao userDao; @Before public void init() { JpaUnitils.injectEntityManagerInto (userDao); } @Test public void testFindByLastName() { List<User> users = userDao.findByLastName(&quot;Doe&quot;); assertPropertyLenientEquals (&quot;userName&quot;, Arrays.asList(&quot;johnDoe&quot;, &quot;janeDoe&quot;), users); } }
  32. 32. Loading test data - example @DataSet @JpaEntityManagerFactory(persistenceUnit=“eshop”, configFiles={“persistence-test.xml”}) public class UserDaoTest extends UnitilsJUnit4 { @PersistenceContext EntityManager entityManager; UserDao userDao; @Before public void init() { JpaUnitils.injectEntityManagerInto(userDao); } @Test public void testFindByLastName() { List<User> users = userDao.findByLastName(&quot;Doe&quot;); assertPropertyLenientEquals(&quot;userName&quot;, Arrays.asList(&quot;johnDoe&quot;, &quot;janeDoe&quot;), users); } }
  33. 33. Loading test data <ul><li>@DataSet </li></ul><ul><ul><li>Dbunit dataset is loaded before each test </li></ul></ul><ul><ul><ul><li>Tables are cleared first </li></ul></ul></ul><ul><ul><li>Default file: same package & name as class </li></ul></ul>UserDaoTest.xml: <?xml version='1.0' encoding='UTF-8'?> <dataset [… XSD declaration …]> <user id=&quot;1&quot; userName=&quot;johnDoe&quot; /> <user id=&quot;2&quot; userName=&quot;janeRoe&quot; /> <user id=&quot;3&quot; userName=&quot;janeDoe&quot; /> </dataset>  Put database in known state before each test
  34. 34. Loading test data - possibilities <ul><li>Custom file name </li></ul><ul><li>Method - specific data set </li></ul><ul><li>Load multiple datasets </li></ul>@DataSet(&quot;UserData.xml&quot;) public class UserDaoTest extends UnitilsJUnit4 { @DataSet(&quot;UserData-adminUser.xml&quot;) public void testFindAdminUsers() { @DataSet({&quot;ReferenceData.xml&quot;, &quot;UserData.xml&quot;}) public class UserDaoTest extends UnitilsJUnit4 {
  35. 35. Loading test data - XSD <ul><li>XSD for validation & auto completion </li></ul><ul><ul><li>Automatically generated by Unitils </li></ul></ul><?xml version='1.0' encoding='UTF-8'?> <dataset xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema- instance&quot; xsi:noNamespaceSchemaLocation=&quot;<path to dataset.xsd file>&quot; > <user id=&quot;1&quot; userName=&quot;johnDoe&quot; age=&quot;54&quot;/> <user id=&quot;2&quot; userName=&quot;janeRoe&quot; lastName=&quot;Roe&quot;/> <user id=&quot;3&quot; userName=&quot;janeDoe&quot; firstName=&quot;Jane&quot;/> </dataset>
  36. 36. Loading test data – multi-schema support <ul><li>Multi – schema dataset support </li></ul><?xml version='1.0' encoding='UTF-8'?> <dataset xmlns:schema1=&quot;SCHEMA1&quot; xmlns:schema2=&quot;SCHEMA2&quot; > < schema1 :user id=&quot;1&quot; userName=&quot;johnDoe&quot; age=&quot;54&quot;/> < schema2 :user id=&quot;2&quot; userName=&quot;janeRoe&quot; lastName=&quot;Roe&quot;/> </dataset>
  37. 37. Loading test data – dbunit issues <ul><li>Solve annoying dbunit issue </li></ul>With Unitils: <?xml version='1.0' encoding='UTF-8'?> <dataset [… namespace declaration …]> <user id=&quot;1&quot; userName=&quot;johnDoe&quot; lastName=&quot;Roe&quot;/> <user id=&quot;2&quot; userName=&quot;janeRoe&quot;/> </dataset> With plain dbunit: <?xml version='1.0' encoding='UTF-8'?> <dataset [… namespace declaration …]> <user id=&quot;1&quot; userName=&quot;johnDoe&quot; lastName=&quot;Roe&quot; /> <user id=&quot;2&quot; userName=&quot;janeRoe&quot; lastName=“[null]&quot;/> </dataset> When using dbunit directly, this is not possible: Once you’ve used a column, you must use it in every record
  38. 38. Verify database contents <ul><li>@ExpectedDataSet </li></ul><ul><ul><li>Verify database contents after test execution </li></ul></ul>UserDaoTest.testCreateNewUser-expected.xml: <?xml version='1.0' encoding='UTF-8'?> <dataset [… namespace declaration …]> <user id=&quot;1&quot; userName=&quot;johnDoe&quot;/> </dataset> @ExpectedDataSet public void testCreateNewUser() { // ... }
  39. 39. Transaction support <ul><li>Run each test in a transaction </li></ul><ul><ul><li>Avoid problems with ‘select for update’ or deferred check constraints
  40. 40. Required in some environments </li></ul></ul><ul><li>Possible to rollback after each test </li></ul><ul><ul><li>Facilitates test isolation: DB stays in original state
  41. 41. Enables using pre-filled test DB </li></ul></ul><ul><li>Default behavior: commit after every test </li></ul><ul><ul><li>Modify using @Transactional </li></ul></ul><ul><li>Powered by spring </li></ul>
  42. 42. Transaction support - example @DataSet @Transactional(TransactionMode.ROLLBACK) @JpaEntityManagerFactory(persistenceUnit=“eshop”, configFiles={“persistence-test.xml”}) public class UserDaoTest extends UnitilsJUnit4 { @PersistenceContext EntityManager entityManager; UserDao userDao; @Before public void init() { JpaUnitils.injectEntityManagerInto(userDao); } @Test public void testFindByLastName() { List<User> users = userDao.findByLastName(&quot;Doe&quot;); assertPropertyLenientEquals(&quot;userName&quot;, Arrays.asList(&quot;johnDoe&quot;, &quot;janeDoe&quot;), users); } }
  43. 43. JPA integration - example @DataSet @JpaEntityManagerFactory(persistenceUnit=“eshop”, configFiles={“persistence-test.xml”}) public class UserDaoTest extends UnitilsJUnit4 { @PersistenceContext EntityManager entityManager; UserDao userDao; @Before public void init() { JpaUnitils.injectEntityManagerInto (userDao); } @Test public void testFindByLastName() { List<User> users = userDao.findByLastName(&quot;Doe&quot;); assertPropertyLenientEquals(&quot;userName&quot;, Arrays.asList(&quot;johnDoe&quot;, &quot;janeDoe&quot;), users); } }
  44. 44. JPA integration <ul><li>@JpaEntityManagerFactory </li></ul><ul><ul><li>Create EntityManagerFactory
  45. 45. Connects with unit test database
  46. 46. New EntityManager for each test </li></ul></ul><ul><ul><ul><li>Attached to unitils transaction </li></ul></ul></ul><ul><ul><li>Powered by spring </li></ul></ul>
  47. 47. JPA integration – persistence providers <ul><li>Supported persistence providers </li></ul><ul><ul><li>Hibernate
  48. 48. Toplink
  49. 49. OpenJPA </li></ul></ul>
  50. 50. JPA integration – mapping test <ul><li>Entity / database mapping test </li></ul><ul><ul><li>Verifies if database structure is in sync with entities
  51. 51. Only works when persistence provider = hibernate </li></ul></ul>@Test public void testMappingToDatabase() { JpaUnitils.assertMappingWithDatabaseConsistent(); } Found mismatches between Java objects and database tables. Applying DDL statements should resolve the problem: alter table PERSON add column lastName varchar(255); alter table PRODUCT add column barCode varchar(255);
  52. 52. Reflection assert - example @DataSet @JpaEntityManagerFactory(persistenceUnit=“eshop”, configFiles={“persistence-test.xml”}) public class UserDaoTest extends UnitilsJUnit4 { @PersistenceContext EntityManager entityManager; UserDao userDao; @Before public void init() { JpaUnitils.injectEntityManagerInto(userDao); } @Test public void testFindByLastName() { List<User> users = userDao.findByLastName(&quot;Doe&quot;); assertPropertyLenientEquals (&quot;userName&quot;, Arrays.asList(&quot;johnDoe&quot;, &quot;janeDoe&quot;), users); } }
  53. 53. Reflection assert <ul><li>ReflectionAssert </li></ul>assertReflectionEquals(expectedUser, actualUser); <ul><ul><li>Compares all fields using reflection
  54. 54. Recursively compares inner objects
  55. 55. Loops over collections and arrays
  56. 56. Reports all differences </li></ul></ul>
  57. 57. Reflection assert - leniency <ul><li>Leniency </li></ul><ul><ul><li>Keep your tests maintainable
  58. 58. Only verify what’s relevant for the test </li></ul></ul><ul><li>Lenient by default: </li></ul><ul><ul><li>Lenient number types
  59. 59. Lenient collection types </li></ul></ul><ul><li>Leniency options: assertLenientEquals ( ... ) </li></ul><ul><ul><li>Lenient order of collections
  60. 60. Ignore java default values (0 or null) </li></ul></ul>
  61. 61. Reflection assert – lenient collection order <ul><li>Ignore order of collections and arrays </li></ul>assertReflectionEquals(expectedCollection, actualCollection, ReflectionComparatorMode.LENIENT_ORDER); assertLenientEquals(expectedCollection, actualCollection); Expected users: [ john , jane ] Actual users: [ jane , john ]
  62. 62. Reflection assert – ignore defaults <ul><li>Ignore java default values: 0 or null </li></ul>assertReflectionEquals(expectedCollection, actualCollection, ReflectionComparatorMode.IGNORE_DEFAULTS); assertLenientEquals(expectedUser, actualUser); Expected id: 0 first name: Jane last name: null Actual id: 123 first name: Jane last name: Doe
  63. 63. Reflection assert – check property value <ul><li>Check property value </li></ul>assertPropertyLenientEquals( &quot; address.houseNr &quot; , 5 , user); <ul><li>Check property value for all elements in collection </li></ul>assertPropertyLenientEquals( “ userName &quot; , Arrays.asList( &quot; johnDoe &quot; , &quot; janeDoe &quot; ), users);
  64. 64. Persistence layer testing - example @DataSet @JpaEntityManagerFactory (persistenceUnit=“eshop”, configFiles={“persistence-test.xml”}) public class UserDaoTest extends UnitilsJUnit4 { @PersistenceContext EntityManager entityManager; UserDao userDao; @Before public void init() { JpaUnitils.injectEntityManagerInto (userDao); } @Test public void testFindByLastName() { List<User> users = userDao.findByLastName(&quot;Doe&quot;); assertPropertyLenientEquals (&quot;userName&quot;, Arrays.asList(&quot;johnDoe&quot;, &quot;janeDoe&quot;), users); } }
  65. 65. Base test class with all plumbing @DataSet @JpaEntityManagerFactory (persistenceUnit=“eshop”, configFiles={“persistence-test.xml”}) public class BaseDaoTest extends UnitilsJUnit4 { @PersistenceContext protected EntityManager entityManager; protected Dao dao = createDao(); @Before public void init() { JpaUnitils.injectEntityManagerInto (dao); } protected abstract DAO createDAO(); }
  66. 66. Test without plumbing public class UserDaoTest extends BaseDaoTest { UserDao userDao = new UserDao(); @Override protected Object getTestedObject() { return userDao; } @Test public void testFindByLastName() { List<User> users = dao.findByLastName(&quot;Doe&quot;); assertPropertyLenientEquals(&quot;userName&quot;, Arrays.asList(&quot;johnDoe&quot;, &quot;janeDoe&quot;), users); } }
  67. 67. Hibernate support - example @DataSet public class UserDaoTest extends UnitilsJUnit4 { @HibernateSessionFactory(“hibernate-test.cfg.xml”) EntityManagerFactory entityManagerFactory; UserDao userDao; @Before // Instantiate UserDao and inject EntityManagerFactory @Test public void testFindByLastName() { List<User> users = userDao.findByLastName(&quot;Doe&quot;); assertPropertyLenientEquals(&quot;userName&quot;, Arrays.asList(&quot;johnDoe&quot;, &quot;janeDoe&quot;), users); } }
  68. 68. Spring integration – DAO example import org.springframework.orm.hibernate3.support.HibernateDaoSupport; public class UserDao extends HibernateDaoSupport { // ... public List<User> findByLastName(String lastName) { return (Long) getHibernateTemplate().findByNamedParam( &quot;from User u where u.lastName = :lastName&quot;, &quot;user&quot;, user).get(0); } // ... }
  69. 69. Spring integration – test example @SpringApplicationContext({“eshop-config.xml”, “test-config.xml”}) @DataSet public class UserDaoTest extends UnitilsJUnit4 { @SpringBean(“userDao”) UserDao userDao; @Test public void testFindByLastName() { List<User> users = userDao.findByLastName(&quot;Doe&quot;); assertPropertyLenientEquals(&quot;userName&quot;, Arrays.asList(&quot;johnDoe&quot;, &quot;janeDoe&quot;), users); } }
  70. 70. Spring integration - configuration eshop-config.xml <bean id=&quot;userDao&quot; class=&quot;eshop.dao.UserDao&quot;> <property name=&quot;sessionFactory&quot; ref=&quot;sessionFactory&quot;/> </bean> <bean id=&quot;sessionFactory&quot; class=&quot;..AnnotationSessionFactoryBean&quot;> <property name=&quot;dataSource&quot; ref=&quot;dataSource&quot;/> <property name=&quot;annotatedClasses&quot;> <list> <value>eshop.model.User</value> </list> </property> </bean> <bean id=&quot;dataSource&quot;> … </bean> test-config.xml <bean id=&quot;dataSource&quot; class=&quot;org.unitils..UnitilsDataSourceFactoryBean&quot;/>
  71. 71. Spring integration <ul><li>@SpringApplicationContext </li></ul><ul><ul><li>Application context is loaded
  72. 72. Typically application & test specific config file </li></ul></ul><ul><li>@SpringBean </li></ul><ul><ul><li>Inject bean from ApplicationContext into test
  73. 73. Other possibilities </li></ul></ul><ul><ul><ul><li>@SpringBeanByName, @SpringBeanByType </li></ul></ul></ul>
  74. 74. Automatic database maintenance <ul><li>Automatic database maintenance </li></ul><ul><ul><li>Currently still part of unitils (2.2)
  75. 75. Split off into DbMaintain project </li></ul></ul><ul><ul><ul><li>1.0 released in february </li></ul></ul></ul><ul><ul><li>Will be removed from Unitils </li></ul></ul>
  76. 76. Why automatic database maintenance? <ul><li>Drawbacks of manual maintenance </li></ul><ul><ul><li>Lot of databases – lot to maintain
  77. 77. What was rolled out where? </li></ul></ul> Time consuming, error prone
  78. 78. Why automatic database maintenance? <ul><li>Fully automatic deployments </li></ul><ul><ul><li>Enables frequent deployments
  79. 79. Tester / customer can trigger deployment </li></ul></ul><ul><ul><ul><li>Shorter feedback cycle </li></ul></ul></ul><ul><ul><li>Enables automatic integration tests </li></ul></ul>
  80. 80. Database maintainer – basic usage <ul><ul><li>Folder with indexed scripts </li></ul></ul><ul><ul><li>Database table stores executed scripts info </li></ul></ul><ul><ul><li>Rollout: Only apply new scripts </li></ul></ul>FILE_NAME VERSION LAST_MODIFIED CHECKSUM EXECUTED_AT SUCCEEDED 01_users.sql 1 1206695947921 15a4be468g 2008-09-17 20:23:12 1 02_roles.sql 1 1206695947996 79a5b32g10 2008-09-18 10:15:12 1 DBMAINTAIN_SCRIPTS dbscripts / 01_users.sql / 02_roles.sql
  81. 81. Database maintainer – script organization <ul><li>Work incremental </li></ul><ul><ul><li>Database change = new script
  82. 82. What’s committed cannot be changed
  83. 83. Sequence is strict </li></ul></ul>dbscripts / incremental / 01_initial / 01_users.sql / 02_sprint1 / 01_roles.sql 02_groups.sql
  84. 84. Database maintainer – script organization <ul><li>Hierarchic organization </li></ul><ul><ul><li>Organize per release, sprint </li></ul></ul>dbscripts / incremental / 01_initial / 01_users.sql / 02_sprint1 / 01_roles.sql 02_groups.sql
  85. 85. Database maintainer – script organization <ul><li>Incremental / repeatable scripts </li></ul><ul><ul><li>Indexed = incremental
  86. 86. Non-indexed = repeatable </li></ul></ul><ul><ul><li>Update incremental script  error
  87. 87. Update repeatable script  re-execute </li></ul></ul>dbscripts / incremental / 01_initial / 01_users.sql / 02_sprint1 / 01_roles.sql 02_groups.sql repeatable / view_users_groups.sql
  88. 88. Database maintainer – post processing <ul><li>Post-processing scripts </li></ul>dbscripts / incremental / 01_initial / 01_users.sql / 02_sprint1 / 01_roles.sql 02_groups.sql repeatable / view_users_groups.sql postprocessing / compile_all.sql create_grants.sql
  89. 89. Database maintainer – multi-db <ul><li>Multi database / db user support </li></ul><ul><ul><li>Define different datasources </li></ul></ul><ul><ul><ul><li>Usually: same DB – different DB user </li></ul></ul></ul><ul><ul><li>Indicate target DB in script name </li></ul></ul><ul><ul><ul><li>Use logical name in script: linked to physical DB at execution time </li></ul></ul></ul>01_products.sql 02_ @users _usergroups.sql
  90. 90. Database maintainer – multi-db <ul><li>Support for patches </li></ul><ul><ul><li>Fix on production branch  merge into DEV </li></ul></ul> Not allowed: Not in correct sequence dbscripts / incremental / 01_v1.0 / 01_users.sql / 02_#patch_add_status.sql / 02_v1.1 / 01_roles.sql 02_groups.sql
  91. 91. Database maintainer – multi-db <ul><li>Support for renames </li></ul><ul><ul><li>Rename scripts / folders
  92. 92. Renumber script / folder indexes
  93. 93. Split scripts into folders
  94. 94. Move scripts from separate folders together </li></ul></ul> Only limitation: relative sequence scripts can't change
  95. 95. Database maintainer & the SCM <ul><li>Database setup is put into version control!
  96. 96. Atomic: Source and db modifications </li></ul><ul><ul><li>Comitted together
  97. 97. Checked out together
  98. 98. Deployed together </li></ul></ul> No temporary failures!
  99. 99. Database script jar <ul><li>Create jar file with scripts </li></ul><ul><ul><li>Self contained: Containing own configuration </li></ul></ul><ul><li>Publish scripts as a deliverable just like war or ear </li></ul>
  100. 100. Database maintainer – multi-db <ul><li>Other dbmaintain operations </li></ul><ul><ul><li>markDatabaseAsUpToDate
  101. 101. clearDatabase
  102. 102. cleanDatabase
  103. 103. disableConstraints
  104. 104. updateSequences </li></ul></ul>
  105. 105. DbMaintain execution <ul><li>Execution using ant </li></ul><ul><li>Command line </li></ul><updateDatabase scriptLocations= &quot; ... &quot; > <database url= &quot; ... &quot; ... /> </updateDatabase> > dbmaintain updateDatabase eshop-db.jar – config dbmaintain-st.properties
  106. 106. Recreation from scratch <ul><li>From scratch option </li></ul><ul><ul><li>Possible to modify indexed script  triggers from-scratch recreation
  107. 107. No data preservation
  108. 108. Perfect for unit / integration test databases </li></ul></ul>
  109. 109. Unitils integration <ul><li>Integration with unitils </li></ul><ul><ul><li>Auto-maintain unit test schema
  110. 110. Check for script updates before running tests
  111. 111. Make db more ‘test friendly’ </li></ul></ul><ul><ul><ul><li>Disable constraints
  112. 112. Update sequences </li></ul></ul></ul>
  113. 113. Disable FK & not-null constraints <ul><li>Why disable FK & not null constraints? </li></ul><ul><ul><li>What we need </li></ul></ul><ul><ul><li>What we need to write: </li></ul></ul><dataset> <user id=&quot;1&quot; username=&quot;jdoe&quot; /> </dataset> <dataset> <user id=&quot;1&quot; username=&quot;jdoe&quot; firstname=&quot;john&quot; lastname=&quot;Doe&quot; role_id=&quot;1&quot; company_id=&quot;1&quot; /> <role id=&quot;1&quot; rolename=&quot;admin&quot; /> <company id=&quot;1&quot; name=“Agit&quot; /> </dataset>
  114. 114. Database maintenance <ul><li>DB maintainer </li></ul><ul><ul><li>Automatic DB post-processing to make it more test-friendly </li></ul></ul><ul><ul><ul><li>Disable foreign key & not null constraints
  115. 115. Increase value of sequences and identity columns </li></ul></ul></ul><ul><ul><li>Generate XSD or DTD for dataset definition </li></ul></ul>
  116. 116. Mock objects support <ul><li>Brand new mock object library
  117. 117. Goals </li></ul><ul><ul><li>Create the ‘best of breed’
  118. 118. Define the simplest possible syntax
  119. 119. Promote best practices </li></ul></ul>
  120. 120. Mock objects support example public class AlertServiceTest extends UnitilsJUnit4 { Mock <Scheduler> mockScheduler; Mock <Messenger> mockMessenger; // Test data setup @Test public void testSendScheduledAlerts() { mockScheduler.returns (alerts).getScheduledAlerts(myUser)); alertService.sendScheduledAlerts(); mockMessenger.assertInvoked() .sendMessage(alert1); mockMessenger.assertInvoked() .sendMessage(alert2); } }
  121. 121. Separate behavior definition from verification <ul><li>Separate behavior definition from verification </li></ul>Compared to EasyMock: mockScheduler.returns(alerts).getScheduledAlerts(myUser); alertService.sendScheduledAlerts(); mockMessenger.assertInvoked().sendMessage(alert1); mockMessenger.assertInvoked().sendMessage(alert2); expect(mockScheduler).getScheduledAlerts(myUser) .andReturn(alerts); mockMessenger.sendMessage(alert1); mockMessenger.sendMessage(alert2); replay(); alertService.sendScheduledAlerts();
  122. 122. Behavior definition syntax <ul><li>Simple, consistent syntax </li></ul><ul><ul><li>Behavior definition
  123. 123. Invocation asserts
  124. 124. No static imports needed </li></ul></ul>Compared to EasyMock: mockObject.returns(value).getA(); mockObject.throws(exception).doSomethingInvalid(); mockObject.assertInvoked().doSomething(); expect(mockObject.getA()).andReturn(value); mockObject.doSomethingInvalid(); expectLastCall().andThrow(exception); mockObject.doSomething();
  125. 125. Behavior definition syntax <ul><li>Verify invocations: sequence not important
  126. 126. Strict sequence </li></ul>mockMessenger. assertInvoked() .sendMessage(alert1); mockMessenger. assertInvoked() .sendMessage(alert2); mockMessenger. assertInvokedInSequence() .sendMessage(alert1); mockMessenger. assertInvokedInSequence() .sendMessage(alert2);
  127. 127. Behavior definition syntax <ul><li>By default all invocations allowed </li></ul><ul><ul><li>Default return values: null, empty collection / array </li></ul></ul><ul><li>Behavior definitions match multiple times
  128. 128. To match only once: </li></ul>mockScheduler.returns(alerts).getScheduledAlerts(myUser); mockScheduler.getMock().getScheduledAlerts(); -> returns alerts mockScheduler.getMock().getScheduledAlerts(); -> returns alerts mockScheduler.onceReturns(alerts).getScheduledAlerts(myUser); mockScheduler.getMock().getScheduledAlerts(); -> returns alerts mockScheduler.getMock().getScheduledAlerts(); -> returns null
  129. 129. Relax argument constraints <ul><li>Mix argument matchers with concrete objects </li></ul><ul><li>EasyMock: Mixing not possible </li></ul>either or mockScheduler.returns(alerts) .getScheduledAlerts( notNull(Date.class), myUser ); expect(mockScheduler).getScheduledAlerts( toDate(“2008/09/18”), myUser ).andReturn(alerts)); expect(mockScheduler).getScheduledAlerts( (Date) notNull(), eq(myUser) ).andReturn(alerts));
  130. 130. Relax argument constraints <ul><li>Null means ‘I don’t care’ </li></ul><ul><li>Is same as </li></ul>mockScheduler.returns(alerts).getScheduledAlerts( null, null ); mockScheduler.returns(alerts) .getScheduledAlerts( (Date)anyObject(), (User)anyObject() );
  131. 131. Relax argument constraints <ul><li>Default argument matching: lenient reflection assert
  132. 132. Copy of objects is taken: If object changed during
  133. 133. test, object at call time is matched </li></ul>mockMessenger.assertInvoked().sendAlert(new Alert(null, null, ChannelType.EMAIL)); mockMessenger.assertInvoked().sendAlert(new Alert(null, null, ChannelType.SMS));
  134. 134. Feedback <ul><li>User feedback </li></ul><ul><ul><li>Observed scenario
  135. 135. Suggested assert statements
  136. 136. Object contents </li></ul></ul>Observed scenario: mockScheduler.getScheduledAlerts ...at mydom.AlertService:55 mockMessenger.send(alert1) ...at mydom.AlertService:76 mockMessenger.send(alert2) ...at mydom.AlertService:76 Suggested assert statements: mockMessenger.assertInvoked().send(alert1); mockMessenger.assertInvoked().send(alert2);
  137. 137. Other features <ul><li>Other features </li></ul><ul><ul><li>Use original implementation for some methods </li></ul></ul><ul><ul><li>‘ Dummy’ objects </li></ul></ul>PartialMock <Messenger> mockMessenger; @Dummy Message alert1, alert2;
  138. 138. Mock injection AlertService alertService; Mock<Scheduler> mockScheduler; Mock<Messenger> mockMessenger; @Before public void setUp() { alertService = new AlertService( mockScheduler. getMock() , mockMessenger. getMock() ); } <ul><li>‘ Manual’ injection </li></ul>
  139. 139. Mock injection @TestedObject AlertService alertService; @InjectIntoByType Mock <Scheduler> mockScheduler ; @InjectIntoByType Mock <Messenger> mockMessenger; <ul><li>Using unitils injection features </li></ul>
  140. 140. Injection <ul><li>Injection of any object into any other object </li></ul><ul><li>Tested object is default target </li></ul><ul><li>Auto-detect target property </li></ul>@InjectInto (target = “targetObject”, property = “targetProperty”) SomeClass injectedObject; TargetClass targetObject; @InjectInto (property = “targetProperty”) SomeClass injectedObject; @TestedObject TargetClass targetObject; @InjectIntoByType SomeClass byTypeInjectedObject; @InjectIntoByName OtherClass byNameInjectedObject; @TestedObject TargetClass targetObject;
  141. 141. Unitils architecture <ul><li>Test execution listener
  142. 142. Modules listening to test execution
  143. 143. Annotations used to instruct modules </li></ul>@DataSet, @SpringBean, @Transactional Test Test Listener Database Module DbUnit Module ... Module
  144. 144. Unitils architecture <ul><li>Need to extend base class </li></ul>org.unitils. UnitilsJUnit3 org.unitils. UnitilsJUnit4 org.unitils. UnitilsTestNG <ul><li>Use custom test runner (JUnit 4 only) </li></ul>@RunWith( UnitilsJUnit4TestClassRunner .class)
  145. 145. Unitils architecture <ul><li>Modules </li></ul><ul><ul><li>DatabaseModule
  146. 146. DbUnitModule
  147. 147. JpaModule
  148. 148. HibernateModule
  149. 149. SpringModule
  150. 150. MockModule
  151. 151. EasyMockModule
  152. 152. InjectModule </li></ul></ul>
  153. 153. Advantages of unitils design <ul><li>Easily extendable and customizable </li></ul><ul><ul><li>Add new modules or switch implementation
  154. 154. Disable modules that you don’t use </li></ul></ul><ul><ul><ul><li>Automatically if a dependency cannot be found </li></ul></ul></ul><ul><ul><li>Different target environments </li></ul></ul><ul><ul><ul><li>Can also be used without spring, hibernate, ... </li></ul></ul></ul><ul><li>Free choice of unit test framework </li></ul><ul><ul><li>JUnit 3, JUnit 4, TestNG </li></ul></ul>
  155. 155. Spring integration <ul><li>Spring offers similar testing framework </li></ul><ul><ul><li>Abstraction of test framework
  156. 156. Wire test with beans from app-ctx
  157. 157. Run tests in transaction </li></ul></ul><ul><li>Upcoming: integration (2.1) </li></ul><ul><ul><li>Use spring test with unitils features </li></ul></ul>
  158. 158. Spring integration @ContextConfiguration({“eshop-config.xml”, “test-config.xml”}) @DataSet public class UserDaoTest extends AbstractTransactionalUnitilsJUnit4SpringContextTests { @AutoWired UserDao userDao; @Test public void testFindByLastName() { List<User> users = userDao.findByLastName(&quot;Doe&quot;); assertPropertyLenientEquals(&quot;userName&quot;, Arrays.asList(&quot;johnDoe&quot;, &quot;janeDoe&quot;), users); } }
  159. 159. Roadmap Q3 2009 Q4 2009 DbMaintain 1.1 Unitils 2.3 Unitils 3.0 Separate modules DbMaintain 1.2 Spring test integration Multi db support Various improvements Maven integration Profiles support
  160. 160. Links <ul><li>www.unitils.org </li></ul><ul><ul><li>Project info
  161. 161. Cookbook (quick start guide)
  162. 162. Tutorial
  163. 163. Forum & issue tracker </li></ul></ul>Mail me: filip.neven@unitils.org
  164. 164. Q&A

×