Your SlideShare is downloading. ×
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,915

Published on

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

No Downloads
Views
Total Views
6,915
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’
      • Provide a good testing environment
      • 4. Remove boilerplate code
      • 5. Automate stuff where possible
      • 6. Help applying best practices
    • 7. Why Unitils?
      • Tackle complexity of persistence layer testing
        • Many practical problems
        • 8. A lot of boilerplate code required
      • Offer all kinds of useful functionalities
        • Assertion using reflection
        • 9. Mock objects
    • 10. Agenda
      • History
      • 11. Features by example
        • Persistence layer testing
        • 12. Reflection assert
        • 13. Database maintenance
        • 14. Mock objects
      • Unitils design
      • 15. Roadmap & summary
    • 16. Introduction
      • Originates from Ordina Testing & QA task force (2005)
        • Brainstorm
        • 17. Testing guidelines: www.unitils.org/guidelines.html
        • 18. Supporting code
       Unitils open source project
    • 19. Features
      • Persistence layer testing
      • Automatic database maintenance
        • DbMaintain
      • General testing utilities
        • Reflection assert
      • Spring integration
      • 21. Mock objects
    • 22. Persistence layer testing
      • Important to test persistence layer
        • Queries are often complex
        • 23. Two separated parts -> mismatches more likely
      • Testing persistence is difficult
        • Test database
        • 24. Provide test data
      • Lot of boilerplate code required
        • Depends on technology: Plain old JDBC, ORM, spring
    • 25. Persistence layer testing guidelines
      • Need control over database & test data
        • Test database
        • 26. Empty database
        • 27. Small dataset per group of related tests
          • Typically one dataset per test class
    • 28. Separate developer schema’s
      • Separate schema per developer
        • Develop in isolation
        • 29. Test in isolation
    • 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
      • @DataSet
        • Dbunit dataset is loaded before each test
          • Tables are cleared first
        • Default file: same package & name as class
      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
      • Custom file name
      • Method - specific data set
      • Load multiple datasets
      @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
      • XSD for validation & auto completion
        • Automatically generated by Unitils
      <?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
      • Multi – schema dataset support
      <?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
      • Solve annoying dbunit issue
      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
      • @ExpectedDataSet
        • Verify database contents after test execution
      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
      • Run each test in a transaction
        • Avoid problems with ‘select for update’ or deferred check constraints
        • 40. Required in some environments
      • Possible to rollback after each test
        • Facilitates test isolation: DB stays in original state
        • 41. Enables using pre-filled test DB
      • Default behavior: commit after every test
        • Modify using @Transactional
      • Powered by spring
    • 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
      • @JpaEntityManagerFactory
        • Create EntityManagerFactory
        • 45. Connects with unit test database
        • 46. New EntityManager for each test
          • Attached to unitils transaction
        • Powered by spring
    • 47. JPA integration – persistence providers
      • Supported persistence providers
    • 50. JPA integration – mapping test
      • Entity / database mapping test
        • Verifies if database structure is in sync with entities
        • 51. Only works when persistence provider = hibernate
      @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
      • ReflectionAssert
      assertReflectionEquals(expectedUser, actualUser);
        • Compares all fields using reflection
        • 54. Recursively compares inner objects
        • 55. Loops over collections and arrays
        • 56. Reports all differences
    • 57. Reflection assert - leniency
      • Leniency
        • Keep your tests maintainable
        • 58. Only verify what’s relevant for the test
      • Lenient by default:
        • Lenient number types
        • 59. Lenient collection types
      • Leniency options: assertLenientEquals ( ... )
        • Lenient order of collections
        • 60. Ignore java default values (0 or null)
    • 61. Reflection assert – lenient collection order
      • Ignore order of collections and arrays
      assertReflectionEquals(expectedCollection, actualCollection, ReflectionComparatorMode.LENIENT_ORDER); assertLenientEquals(expectedCollection, actualCollection); Expected users: [ john , jane ] Actual users: [ jane , john ]
    • 62. Reflection assert – ignore defaults
      • Ignore java default values: 0 or null
      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
      • Check property value
      assertPropertyLenientEquals( &quot; address.houseNr &quot; , 5 , user);
      • Check property value for all elements in collection
      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
      • @SpringApplicationContext
        • Application context is loaded
        • 72. Typically application & test specific config file
      • @SpringBean
        • Inject bean from ApplicationContext into test
        • 73. Other possibilities
          • @SpringBeanByName, @SpringBeanByType
    • 74. Automatic database maintenance
      • Automatic database maintenance
        • Currently still part of unitils (2.2)
        • 75. Split off into DbMaintain project
          • 1.0 released in february
        • Will be removed from Unitils
    • 76. Why automatic database maintenance?
      • Drawbacks of manual maintenance
        • Lot of databases – lot to maintain
        • 77. What was rolled out where?
       Time consuming, error prone
    • 78. Why automatic database maintenance?
      • Fully automatic deployments
        • Enables frequent deployments
        • 79. Tester / customer can trigger deployment
          • Shorter feedback cycle
        • Enables automatic integration tests
    • 80. Database maintainer – basic usage
        • Folder with indexed scripts
        • Database table stores executed scripts info
        • Rollout: Only apply new scripts
      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
      • Work incremental
        • Database change = new script
        • 82. What’s committed cannot be changed
        • 83. Sequence is strict
      dbscripts / incremental / 01_initial / 01_users.sql / 02_sprint1 / 01_roles.sql 02_groups.sql
    • 84. Database maintainer – script organization
      • Hierarchic organization
        • Organize per release, sprint
      dbscripts / incremental / 01_initial / 01_users.sql / 02_sprint1 / 01_roles.sql 02_groups.sql
    • 85. Database maintainer – script organization
      • Incremental / repeatable scripts
        • Indexed = incremental
        • 86. Non-indexed = repeatable
        • Update incremental script  error
        • 87. Update repeatable script  re-execute
      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
      • Post-processing scripts
      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
      • Multi database / db user support
        • Define different datasources
          • Usually: same DB – different DB user
        • Indicate target DB in script name
          • Use logical name in script: linked to physical DB at execution time
      01_products.sql 02_ @users _usergroups.sql
    • 90. Database maintainer – multi-db
      • Support for patches
        • Fix on production branch  merge into DEV
       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
      • Support for renames
        • Rename scripts / folders
        • 92. Renumber script / folder indexes
        • 93. Split scripts into folders
        • 94. Move scripts from separate folders together
       Only limitation: relative sequence scripts can't change
    • 95. Database maintainer & the SCM
      • Database setup is put into version control!
      • 96. Atomic: Source and db modifications
        • Comitted together
        • 97. Checked out together
        • 98. Deployed together
       No temporary failures!
    • 99. Database script jar
      • Create jar file with scripts
        • Self contained: Containing own configuration
      • Publish scripts as a deliverable just like war or ear
    • 100. Database maintainer – multi-db
      • Other dbmaintain operations
    • 105. DbMaintain execution
      • Execution using ant
      • Command line
      <updateDatabase scriptLocations= &quot; ... &quot; > <database url= &quot; ... &quot; ... /> </updateDatabase> > dbmaintain updateDatabase eshop-db.jar – config dbmaintain-st.properties
    • 106. Recreation from scratch
      • From scratch option
        • Possible to modify indexed script  triggers from-scratch recreation
        • 107. No data preservation
        • 108. Perfect for unit / integration test databases
    • 109. Unitils integration
      • Integration with unitils
        • Auto-maintain unit test schema
        • 110. Check for script updates before running tests
        • 111. Make db more ‘test friendly’
          • Disable constraints
          • 112. Update sequences
    • 113. Disable FK & not-null constraints
      • Why disable FK & not null constraints?
        • What we need
        • What we need to write:
      <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
      • DB maintainer
        • Automatic DB post-processing to make it more test-friendly
          • Disable foreign key & not null constraints
          • 115. Increase value of sequences and identity columns
        • Generate XSD or DTD for dataset definition
    • 116. Mock objects support
      • Brand new mock object library
      • 117. Goals
        • Create the ‘best of breed’
        • 118. Define the simplest possible syntax
        • 119. Promote best practices
    • 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
      • Separate behavior definition from verification
      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
      • Simple, consistent syntax
        • Behavior definition
        • 123. Invocation asserts
        • 124. No static imports needed
      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
      • Verify invocations: sequence not important
      • 126. Strict sequence
      mockMessenger. assertInvoked() .sendMessage(alert1); mockMessenger. assertInvoked() .sendMessage(alert2); mockMessenger. assertInvokedInSequence() .sendMessage(alert1); mockMessenger. assertInvokedInSequence() .sendMessage(alert2);
    • 127. Behavior definition syntax
      • By default all invocations allowed
        • Default return values: null, empty collection / array
      • Behavior definitions match multiple times
      • 128. To match only once:
      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
      • Mix argument matchers with concrete objects
      • EasyMock: Mixing not possible
      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
      • Null means ‘I don’t care’
      • Is same as
      mockScheduler.returns(alerts).getScheduledAlerts( null, null ); mockScheduler.returns(alerts) .getScheduledAlerts( (Date)anyObject(), (User)anyObject() );
    • 131. Relax argument constraints
      • Default argument matching: lenient reflection assert
      • 132. Copy of objects is taken: If object changed during
      • 133. test, object at call time is matched
      mockMessenger.assertInvoked().sendAlert(new Alert(null, null, ChannelType.EMAIL)); mockMessenger.assertInvoked().sendAlert(new Alert(null, null, ChannelType.SMS));
    • 134. Feedback
      • User feedback
        • Observed scenario
        • 135. Suggested assert statements
        • 136. Object contents
      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
      • Other features
        • Use original implementation for some methods
        • ‘ Dummy’ objects
      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() ); }
      • ‘ Manual’ injection
    • 139. Mock injection @TestedObject AlertService alertService; @InjectIntoByType Mock <Scheduler> mockScheduler ; @InjectIntoByType Mock <Messenger> mockMessenger;
      • Using unitils injection features
    • 140. Injection
      • Injection of any object into any other object
      • Tested object is default target
      • Auto-detect target property
      @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
      • Test execution listener
      • 142. Modules listening to test execution
      • 143. Annotations used to instruct modules
      @DataSet, @SpringBean, @Transactional Test Test Listener Database Module DbUnit Module ... Module
    • 144. Unitils architecture
      • Need to extend base class
      org.unitils. UnitilsJUnit3 org.unitils. UnitilsJUnit4 org.unitils. UnitilsTestNG
      • Use custom test runner (JUnit 4 only)
      @RunWith( UnitilsJUnit4TestClassRunner .class)
    • 145. Unitils architecture
      • Modules
    • 153. Advantages of unitils design
      • Easily extendable and customizable
        • Add new modules or switch implementation
        • 154. Disable modules that you don’t use
          • Automatically if a dependency cannot be found
        • Different target environments
          • Can also be used without spring, hibernate, ...
      • Free choice of unit test framework
        • JUnit 3, JUnit 4, TestNG
    • 155. Spring integration
      • Spring offers similar testing framework
        • Abstraction of test framework
        • 156. Wire test with beans from app-ctx
        • 157. Run tests in transaction
      • Upcoming: integration (2.1)
        • Use spring test with unitils features
    • 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
      • www.unitils.org
      Mail me: filip.neven@unitils.org
    • 164. Q&A

    ×