Your SlideShare is downloading. ×
0
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Unit testing: unitils & dbmaintain
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Unit testing: unitils & dbmaintain

6,991

Published on

Published in: Technology
0 Comments
7 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
6,991
On Slideshare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
125
Comments
0
Likes
7
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide
  • Transcript

    • 1. Unit testing unitils - dbmaintain Filip Neven
    • 2. Presentation goal Demonstrate the added value Unitils can give to your projects
    • 3. Unitils ‘Mission statement’ <ul><li>Provide a good testing environment
    • 4. Remove boilerplate code
    • 5. Automate stuff where possible
    • 6. Help applying best practices </li></ul>
    • 7. Why Unitils? <ul><li>Tackle complexity of persistence layer testing </li></ul><ul><ul><li>Many practical problems
    • 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. Mock objects </li></ul></ul>
    • 10. Agenda <ul><li>History
    • 11. Features by example </li></ul><ul><ul><li>Persistence layer testing
    • 12. Reflection assert
    • 13. Database maintenance
    • 14. Mock objects </li></ul></ul><ul><li>Unitils design
    • 15. Roadmap & summary </li></ul>
    • 16. Introduction <ul><li>Originates from Ordina Testing & QA task force (2005) </li></ul><ul><ul><li>Brainstorm
    • 17. Testing guidelines: www.unitils.org/guidelines.html
    • 18. Supporting code </li></ul></ul> Unitils open source project
    • 19. Features <ul><li>Persistence layer testing </li></ul><ul><ul><li>JPA
    • 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. Mock objects </li></ul>
    • 22. Persistence layer testing <ul><li>Important to test persistence layer </li></ul><ul><ul><li>Queries are often complex
    • 23. Two separated parts -> mismatches more likely </li></ul></ul><ul><li>Testing persistence is difficult </li></ul><ul><ul><li>Test database
    • 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. Persistence layer testing guidelines <ul><li>Need control over database & test data </li></ul><ul><ul><li>Test database
    • 26. Empty database
    • 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. Separate developer schema’s <ul><li>Separate schema per developer </li></ul><ul><ul><li>Develop in isolation
    • 29. Test in isolation </li></ul></ul>
    • 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. JPA integration <ul><li>@JpaEntityManagerFactory </li></ul><ul><ul><li>Create EntityManagerFactory
    • 45. Connects with unit test database
    • 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. JPA integration – persistence providers <ul><li>Supported persistence providers </li></ul><ul><ul><li>Hibernate
    • 48. Toplink
    • 49. OpenJPA </li></ul></ul>
    • 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. 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. 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. Reflection assert <ul><li>ReflectionAssert </li></ul>assertReflectionEquals(expectedUser, actualUser); <ul><ul><li>Compares all fields using reflection
    • 54. Recursively compares inner objects
    • 55. Loops over collections and arrays
    • 56. Reports all differences </li></ul></ul>
    • 57. Reflection assert - leniency <ul><li>Leniency </li></ul><ul><ul><li>Keep your tests maintainable
    • 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. Lenient collection types </li></ul></ul><ul><li>Leniency options: assertLenientEquals ( ... ) </li></ul><ul><ul><li>Lenient order of collections
    • 60. Ignore java default values (0 or null) </li></ul></ul>
    • 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. Spring integration <ul><li>@SpringApplicationContext </li></ul><ul><ul><li>Application context is loaded
    • 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. Other possibilities </li></ul></ul><ul><ul><ul><li>@SpringBeanByName, @SpringBeanByType </li></ul></ul></ul>
    • 74. Automatic database maintenance <ul><li>Automatic database maintenance </li></ul><ul><ul><li>Currently still part of unitils (2.2)
    • 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. Why automatic database maintenance? <ul><li>Drawbacks of manual maintenance </li></ul><ul><ul><li>Lot of databases – lot to maintain
    • 77. What was rolled out where? </li></ul></ul> Time consuming, error prone
    • 78. Why automatic database maintenance? <ul><li>Fully automatic deployments </li></ul><ul><ul><li>Enables frequent deployments
    • 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. 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. Database maintainer – script organization <ul><li>Work incremental </li></ul><ul><ul><li>Database change = new script
    • 82. What’s committed cannot be changed
    • 83. Sequence is strict </li></ul></ul>dbscripts / incremental / 01_initial / 01_users.sql / 02_sprint1 / 01_roles.sql 02_groups.sql
    • 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. Database maintainer – script organization <ul><li>Incremental / repeatable scripts </li></ul><ul><ul><li>Indexed = incremental
    • 86. Non-indexed = repeatable </li></ul></ul><ul><ul><li>Update incremental script  error
    • 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. 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. 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. 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. Database maintainer – multi-db <ul><li>Support for renames </li></ul><ul><ul><li>Rename scripts / folders
    • 92. Renumber script / folder indexes
    • 93. Split scripts into folders
    • 94. Move scripts from separate folders together </li></ul></ul> Only limitation: relative sequence scripts can't change
    • 95. Database maintainer & the SCM <ul><li>Database setup is put into version control!
    • 96. Atomic: Source and db modifications </li></ul><ul><ul><li>Comitted together
    • 97. Checked out together
    • 98. Deployed together </li></ul></ul> No temporary failures!
    • 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. Database maintainer – multi-db <ul><li>Other dbmaintain operations </li></ul><ul><ul><li>markDatabaseAsUpToDate
    • 101. clearDatabase
    • 102. cleanDatabase
    • 103. disableConstraints
    • 104. updateSequences </li></ul></ul>
    • 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. Recreation from scratch <ul><li>From scratch option </li></ul><ul><ul><li>Possible to modify indexed script  triggers from-scratch recreation
    • 107. No data preservation
    • 108. Perfect for unit / integration test databases </li></ul></ul>
    • 109. Unitils integration <ul><li>Integration with unitils </li></ul><ul><ul><li>Auto-maintain unit test schema
    • 110. Check for script updates before running tests
    • 111. Make db more ‘test friendly’ </li></ul></ul><ul><ul><ul><li>Disable constraints
    • 112. Update sequences </li></ul></ul></ul>
    • 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. 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. 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. Mock objects support <ul><li>Brand new mock object library
    • 117. Goals </li></ul><ul><ul><li>Create the ‘best of breed’
    • 118. Define the simplest possible syntax
    • 119. Promote best practices </li></ul></ul>
    • 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. 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. Behavior definition syntax <ul><li>Simple, consistent syntax </li></ul><ul><ul><li>Behavior definition
    • 123. Invocation asserts
    • 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. Behavior definition syntax <ul><li>Verify invocations: sequence not important
    • 126. Strict sequence </li></ul>mockMessenger. assertInvoked() .sendMessage(alert1); mockMessenger. assertInvoked() .sendMessage(alert2); mockMessenger. assertInvokedInSequence() .sendMessage(alert1); mockMessenger. assertInvokedInSequence() .sendMessage(alert2);
    • 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. 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. 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. 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. Relax argument constraints <ul><li>Default argument matching: lenient reflection assert
    • 132. Copy of objects is taken: If object changed during
    • 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. Feedback <ul><li>User feedback </li></ul><ul><ul><li>Observed scenario
    • 135. Suggested assert statements
    • 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. 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. 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. Mock injection @TestedObject AlertService alertService; @InjectIntoByType Mock <Scheduler> mockScheduler ; @InjectIntoByType Mock <Messenger> mockMessenger; <ul><li>Using unitils injection features </li></ul>
    • 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. Unitils architecture <ul><li>Test execution listener
    • 142. Modules listening to test execution
    • 143. Annotations used to instruct modules </li></ul>@DataSet, @SpringBean, @Transactional Test Test Listener Database Module DbUnit Module ... Module
    • 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. Unitils architecture <ul><li>Modules </li></ul><ul><ul><li>DatabaseModule
    • 146. DbUnitModule
    • 147. JpaModule
    • 148. HibernateModule
    • 149. SpringModule
    • 150. MockModule
    • 151. EasyMockModule
    • 152. InjectModule </li></ul></ul>
    • 153. Advantages of unitils design <ul><li>Easily extendable and customizable </li></ul><ul><ul><li>Add new modules or switch implementation
    • 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. Spring integration <ul><li>Spring offers similar testing framework </li></ul><ul><ul><li>Abstraction of test framework
    • 156. Wire test with beans from app-ctx
    • 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. 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. 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. Links <ul><li>www.unitils.org </li></ul><ul><ul><li>Project info
    • 161. Cookbook (quick start guide)
    • 162. Tutorial
    • 163. Forum & issue tracker </li></ul></ul>Mail me: filip.neven@unitils.org
    • 164. Q&A

    ×