Unit testing: unitils & dbmaintain
Upcoming SlideShare
Loading in...5
×
 

Like this? Share it with your network

Share

Unit testing: unitils & dbmaintain

on

  • 8,679 views

 

Statistics

Views

Total Views
8,679
Views on SlideShare
7,842
Embed Views
837

Actions

Likes
7
Downloads
122
Comments
0

8 Embeds 837

http://www.varyonic.com 533
http://www.bejug.org 231
http://blog.oxongeek.org 32
http://www.slideshare.net 24
http://www.bejug.be 8
https://duckduckgo.com 5
http://bejug.org 2
http://translate.googleusercontent.com 2
More...

Accessibility

Categories

Upload Details

Uploaded via as OpenOffice

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Unit testing: unitils & dbmaintain Presentation 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
      • JPA
      • 20. Hibernate
    • 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
      • Hibernate
      • 48. Toplink
      • 49. OpenJPA
  • 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
      • markDatabaseAsUpToDate
      • 101. clearDatabase
      • 102. cleanDatabase
      • 103. disableConstraints
      • 104. updateSequences
  • 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
      • DatabaseModule
      • 146. DbUnitModule
      • 147. JpaModule
      • 148. HibernateModule
      • 149. SpringModule
      • 150. MockModule
      • 151. EasyMockModule
      • 152. InjectModule
  • 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
      • Project info
      • 161. Cookbook (quick start guide)
      • 162. Tutorial
      • 163. Forum & issue tracker
    Mail me: filip.neven@unitils.org
  • 164. Q&A