Cookbook

This page helps you to get started quickly with unitils. Code and configuration are explained using simple examples.

This cookbook contains only typical configuration. More elaborate information about unitils and its configuration can be found in the tutorial. A complete documented reference of all possible configuration options can be found in unitils-default.properties.

The third party libraries required by unitils can be found on the dependencies page.

Reflection assert

Following examples demonstrate the usage of the reflection assert utility. All assert statements are successful:

import static org.unitils.reflectionassert.ReflectionAssert.*;

// Exact field-by-field comparison
assertReflectionEquals(new Person("John", "Doe", new Address("New street", 5, "Brussels")), 
                                 new Person("John", "Doe", new Address("New street", 5, "Brussels"));
  
// Ignore Null / 0 values in the expected object
assertReflectionEquals(new Person("John", null, new Address("New street", 0, null)),
                                 new Person("John", "Doe", new Address("New street", 5, "Brussels"), 
                                 ReflectionComparatorMode.IGNORE_DEFAULTS); 
  
// Ignore collection order
assertReflectionEquals(Arrays.asList(new Person("John"), new Person("Jane")),
                                 new Person[] {new Person("Jane"), new Person("John")}, 
                                 ReflectionComparatorMode.LENIENT_ORDER);
  
// Ignore null/0 values + collection order
assertLenientEquals(Arrays.asList(new Person("John"), null),
                                 new Person[] {new Person("Jane", "Doe"), new Person("John", "Doe")});

// Check only the firstName property 
assertPropertyLenientEquals("firstName", Arrays.asList("John", "Jane"),
                                 new Person[] {new Person("Jane", "Doe"), new Person("John", "Doe")});

Mock objects

Following example demonstrates the mock objects support. It's a test for an alert service: the sendScheduledAlerts() method requests all scheduled alerts from an AlertSchedulerService, and sends them using a MessageSenderService.

import static org.unitils.mock.ArgumentMatchers.*;

public class AlertServiceTest extends UnitilsJUnit4 {

    AlertService alertService;
        List<Message> alerts;
        @Dummy Message alert1, alert2;                 // Dummy objects
    
    Mock<SchedulerService> mockSchedulerService;   // Mock objects
    Mock<MessageService> mockMessageService;

    @Before
    public void init() {
        alertService = new AlertService(mockSchedulerService.getMock(), mockMessageService.getMock());
        alerts = Arrays.asList(alert1, alert2);
    }
        
    @Test 
    public void testSendScheduledAlerts() {
        mockSchedulerService.returns(alerts).getScheduledAlerts(null); // Definition of behavior, null means 'any argument'
            
        alertService.sendScheduledAlerts();
                
        mockMessageService.assertInvoked().sendMessage(alert1);         // Invocation assert
        mockMessageService.assertInvoked().sendMessage(same(alert2));   // Argument matcher
    }
}

The example demonstrates following features:

  • Behavior of mock objects can be defined using the notation mockObject.returns(...).methodCall(...). Passing null as an argument in a behavior definition causes the value of this argument to be ignored. You can also use raises(...) to make a method throw an exception, or performs(...) to specify custom behavior. If no behavior is specified, methods return default values such as null, 0, false or an empty collection.
  • You can verify that certain calls were made on a mock object by using the notation mockObject.assertInvoked().methodCall(...). You can use mockObject.assertInvokedInSequence().methodCall(...) to ensure the calls were made in a certain sequence. With mockObject.assertNotInvoked().methodCall(...) you can explicitly verify that a certain invocation didn't occur or you can use MockUnitils.assertNoMoreInvocations() to make sure no other invocation occurred, except for the ones you verified.
  • By default, expected arguments are compared with actual arguments using lenient reflection comparison: The fields are compared using reflection, the order of collections is ignored and fields that are null, 0 or false in the expected object are ignored. If you want an argument to be ignored altogether, you can simply use null. Argument matchers can be used if other behavior is desired: available argument matchers are notNull, isNull, same, eq, refEq and lenEq. Argument matchers, concrete objects and null can be combined in the same call.
  • Often you need an instance of some domain or value object without the contents of the object being important. For this you can use dummy objects. You can obtain a dummy object by annotating a field with @Dummy or by calling MockUnitils.createDummy(dummyObjectClass). The class doesn't need to offer an empty constructor.
    • To obtain a mock object, simply declare Mock&lt;MyClass&gt; as a field of your test, you don't have to instantiate it. You can also obtain a mock using MockUnitils.createMock(mockObjectClass). You can also use 'partial' mocks by declaring the field as PartialMock&lt;MyClass&gt; or by calling MockUnitils.createPartialMock(mockObjectClass): In a partial mock, methods keep their original behavior unless you specify a different one.
    • When a test fails, a detailed report is shown listing the observed mock invocations with links to the source code and the contents of all objects involved, and suggested assert statements that can be used as a basis for your own asserts.

Injection of mocks

The fixture of the last test can be rewritten as follows, making use of unitils' injection support:

    List<Message> alerts;
    @Dummy Message alert1, alert2;
    
    @InjectIntoByType                        // Is injected into a property of type SchedulerService of the tested object
    Mock<SchedulerService> mockSchedulerService;
    @InjectInto(property = "messageService") // Is injected into the messageService property of the tested object
    Mock<MessageService> mockMessageService;

    @TestedObject
    AlertService alertService;    // The tested object is automatically instantiated
        
    @Before
    public void init() {
        alerts = Arrays.asList(alert1, alert2);
    }
  • The object referenced by the field annotated with @InjectInto is injected to the the object referenced by the field annotated with @TestedObject, in the specified property. The target property is automatically determined by type when using @InjectIntoByType, or by name when using @InjectIntoByName. The target can also be specified explicitly using the target attribute.
  • The field annotated with @TestedObject is automatically instantiated with an instance of the declared type, if necessary (i.e. if not instantiated during test setup) and possible (i.e. if the declared type is a non-abstract class and offers an empty constructor).

EasyMock support

This example demonstrates the EasyMock module.

public class UserServiceTest extends UnitilsJUnit4 {
    
    @Mock 
    @InjectIntoByType
    protected UserDAO mockUserDao;
  
    @TestedObject
    protected UserService userService;

    @Test
    public void testRaiseSalary() {        
        expect(userDao.findAllUsers()).andReturn(Arrays.asList(new User()));
        expect(userDao.updateSalary(null, 100));     
        EasyMockUnitils.replay();
    
        userService.raiseSalaryOfAllUsers(100);
    }    
}

Description

  • A mock object (using EasyMock) of type UserDAO is created and assigned to the mockUserDao field
  • An instance of UserService is created and assigned to the field userService, since this field was still null just before the execution of testRaiseSalary.
  • The contents of the field mockUserDao is injected into a property of userService of type UserDAO.
  • During the test, we first record the expected behavior. Arguments are matched using lenient reflection equals: ignoring null, 0 and false and the order of collections
  • EasyMockUnitils.replay() is called to call replay on all mocks that were created during the test
  • The method under test is invoked
  • When the test finishes, Unitils automatically calls verify() on every mock object

Testing the persistence layer

Since Unitils 1.1, you need spring 2.0 or above in your classpath, if you want to make use of unitils database, JPA or hibernate support. This is because under the hoods, spring is used for transactions and for integration with JPA or hibernate. This does not mean you need to use spring in your application code, you can keep spring as a test- dependency only.

To enable testing your persistence layer, you should start with setting up a test database for every developer in the team. In the configuration shown below, we assume that separate test schemas were created on the same database instance.

Start by creating a file named unitils.properties and make it available in your classpath. It should contain following properties:

# Name or path of the user specific properties file. This file should contain the necessary parameters to connect to the
# developer's own unit test schema. It is recommended to override the name of this file in the project specific properties
# file, to include the name of the project. The system will try to find this file in the classpath, the user home folder
# (recommended) or the local filesystem.
unitils.configuration.localFileName=unitils-<myproject>-local.properties

# Properties for the PropertiesDataSourceFactory
database.driverClassName=<my driver classname>
database.url=<my database connection url>

# This property specifies the underlying DBMS implementation. Supported values are 'oracle', 'db2', 'mysql' and 'hsqldb'.
# The value of this property defines which vendor specific implementations of DbSupport and ConstraintsDisabler are chosen.
database.dialect=<my database dialect>

Next, create a file unitils-<myproject>-local.properties and put this file in the local user home directory. The file should contain following properties:

database.userName=<developers database login username>
database.password=<developers database login password>
database.schemaNames=<developers database schema name>

This way, every developer in the team connects to the same database instance, but connects with a different user and works on a different database schema. Following is an example of a typical database test:

public class UserDaoTest extends UnitilsJUnit4 {
    
    @TestDataSource
    private DataSource dataSource;
    
    private UserDao userDao;
        
    @Before
    public void setUp() {
        userDao = new UserDao();
        userDao.setDataSource(dataSource);
    }
    
    @DataSet
    @Test
    public void testFindUserByLastName() {
        List<User> users = userDao.findByLastName("Doe");
        ReflectionAssert.assertPropertyLenientEquals("firstName", Arrays.asList("John", "Jane"), users);
    }
}

In the same package, we create a test data file named UserDaoTest.xml:

<?xml version='1.0' encoding='UTF-8'?>
<dataset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="<path to dataset.xsd file>">
    <user firstname="John" lastname="Doe"/>
    <user firstname="Jane" lastname="Doe"/>
    <user firstname="Jack" lastname="Smith"/>
</dataset>

Description

  • A DataSource is created that provides access to the test database configured in unitils.properties and unitils-<myproject>-local.properties and is injected into the dataSource field
    • A transaction is started
  • In the setUp method, a new instance of UserDao is created and configured with the test DataSource
  • Unitils looks for a DbUnit dataset file named UserDaoTest.xml, and loads it into the database
  • The test method is invoked
  • Using ReflectionAssert, the first names of the users are compared with the expected names ignoring the actual order of the list
  • After finishing the test, the transaction is committed and closed

Rollback after each test

By default, each test is executed in a transaction, which is committed in the end. If you want your transactions to rollback after every test, annotate the class or method with @Transactional(TransactionMode.ROLLBACK).

Automatic maintenance of test databases

To enable automatic maintenance of the developers' test databases, start with creating a database scripts folder. Add this folder to your source control system. Next, add following properties to unitils.properties:

# If set to true, the DBMaintainer will be used to update the unit test database schema. This is done once for each
# test run, when creating the DataSource that provides access to the unit test database.
updateDataBaseSchema.enabled=true

# Comma separated list of directories and files in which the database update scripts are located. Directories in this
# list are recursively searched for files.
dbMaintainer.script.locations=<Paths to your database update script files>

# DbUnit database XSD directory
dataSetStructureGenerator.xsd.dirName=<Path to your database XSD directory>

# Set this property to true if the dbmaintain_scripts table should be created automatically if not found.
# If false, an exception is thrown when the table is not found, indicating how to create it manually. 
# This property is false by default to be sure that a database is cleared by accident. If an executed 
# scripts table is available, we assume it to be a database managed by dbmaintain.
dbMaintainer.autoCreateExecutedScriptsTable=false

For every update to the database structure, create a DDL script and add it to the database scripts folder. The name of this script must comply with following naming convention: <index>_<some name>.sql. For example:

dbscripts / 001_user_table.sql
            002_company_table.sql

Unitils detects that a script was added and will execute it on the database. If one of the existing scripts is altered, the database is dropped and created from scratch, re-executing all scripts. When the database is updated, XSD files are generated that can be used for validation and auto-completion when writing DBUnit data sets.

A lot more features are offered by the DB maintainer, such as hierarchical organization of scripts, repeatable and post-processing scripts. Read the tutorial for more information.

Test a JPA DAO

Since unitils 1.1, support for JPA is offered, with hibernate, openjpa and toplink as supported persistence providers.

To make use of unitils' JPA support, make sure the datasource is configured correctly as described above and that you have your JPA provider's libraries and spring (2.0 or +) in your classpath. Note: if you use spring as IOC container in your application code, the JPA configuration can also be performed from within an application context (See below).

First of all, you must tell unitils which JPA provider you use, by setting jpa.persistenceProvider to hibernate, openjpa or toplink in unitils.properties:

jpa.persistenceProvider=hibernate

Following is an example of a test:

@JpaEntityManagerFactory(persistenceUnit = "test", configFile = "META-INF/persistence-test.xml")
public class UserDaoTest extends UnitilsJUnit4 {

    @PersistenceContext
        EntityManager entityManager;
    
    UserDao userDao;
    
    @Before
    public void setUp() {
        userDao = new UserDao();
        JpaUnitils.injectEntityManagerInto(userDao);
    }
  
    @Test
    public void testFindUserByLastName() {
        List<User> users = userDao.findByLastName("Doe");
        assertPropertyLenientEquals("firstName", Arrays.asList("John", "Jane"), users);
    }
}

Using the @JpaEntityManagerFactory annotation, we configure the JPA persistence unit which is used in the test. The name of the persistence unit must be indicated using the persistenceUnit attribute. The config file attribute is optional. If omitted, the JPA default META-INF/persistence.xml is loaded.

Unitils injects the EntityManagerFactory and EntityManager into fields / setters annotated with the standard JPA @PersistenceUnit and @PersistenceContext annotations.

Important note: You should not obtain your EntityManager by invoking entityManagerFactory.createEntityManager()! An EntityManger obtained this way won't participate in the test's transaction! If you need to obtain an EntityManager programatically, use JpaUnitils.getEntityManager().

Also note that JPA tests must always be run in a transaction.

Database mapping test

Unitils is shipped with a ready-to-use test that verifies if the mapping of all your JPA entities is consistent with the database structure. To use it, you should write a test that looks like the following:

@JpaEntityManagerFactory(persistenceUnit = "test", configFile = "META-INF/persistence-test.xml")
public class HibernateMappingTest extends UnitilsJUnit4 {
    
    @Test
    public void testMappingToDatabase() {        
        JpaUnitils.assertMappingWithDatabaseConsistent();
    }
}

Note that, if you use toplink as persistence provider, you need to run your tests with a JVM agent to enable load-time bytecode modification. We use the spring-agent.jar for this purpose. You enable the spring agent by adding following JVM option:

-javaagent:/path/to/spring-agent.jar

Test a hibernate DAO

To make use of Unitils' Hibernate support, first make sure the database support is configured correctly as described above and that you have hibernate and spring (2.0+) in your classpath. Note: if you use spring as IOC container in your application code, the Hibernate configuration can also be performed from an application context (See below).

Set the property HibernateModule.configuration.implClassName to the subclass of org.hibernate.cfg.Configuration that you want to use. By default an instance of org.hibernate.cfg.AnnotationConfiguration will be created. If you don't make use of Hibernate with annotations, change the value of this property to the following:

HibernateModule.configuration.implClassName=org.hibernate.cfg.Configuration

Following is an example of a test with Hibernate:

@HibernateSessionFactory("hibernate.cfg.xml")
public class UserDaoTest extends UnitilsJUnit4 {

    @HibernateSessionFactory
    private SessionFactory sessionFactory;
    
    private UserDao userDao;
    
    @Before
    public void setUp() {
        userDao = new UserDao();
        userDao.setSessionFactory(sessionFactory);
    }
  
    @Test
    public void testFindUserByLastName() {
        List<User> users = userDao.findByLastName("Doe");
        assertPropertyLenientEquals("firstName", Arrays.asList("John", "Jane"), users);
    }
}

In the example shown above, Unitils loads an hibernate SessionFactory and configures it with the file hibernate.cfg.xml, which must be available in the classpath. Unitils injects this SessionFactory in all fields or setters annotated with @HibernateSessionFactory, before starting a transaction and starting with the execution of the setUp() method.

Database mapping test for hibernate

Unitils is shipped with a ready-to-use test that verifies if the mapping of all your mapped classes is consistent with the database structure. Note that this test will only work if you use hibernate as persistence provider. You should write a test that looks like the following:

@HibernateSessionFactory("hibernate.cfg.xml")
public class HibernateMappingTest extends UnitilsJUnit4 {
    
    @Test
    public void testMappingToDatabase() {        
        HibernateUnitils.assertMappingWithDatabaseConsistent();
    }
}

Spring integration

Following is an example of a test in which we use a hibernate SessionFactory configured in spring:

@SpringApplicationContext({"services-config.xml", "test-config.xml"})
public class UserDaoTest extends UnitilsJUnit4 {
    
    @SpringBean("userDao")
    protected UserDao userDao;
  
    @Test
    public void testFindUserByLastName() {
        List<User> users = userDao.findByLastName("Doe");
        assertPropertyLenientEquals("firstName", Arrays.asList("John", "Jane"), users);
    }
  
    @Test
    public void testMappingWithDatabase() {        
        HibernateUnitils.assertMappingWithDatabaseConsistent();
    }
}

This is the configuration file: services-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans>

    <bean id="userDao" class="org.unitils.cookbook.UserDao">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="annotatedClasses">
            <list>
                <value>org.unitils.sample.User</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <value>
            ...
            </value>
        </property>
    </bean>
  
</beans>

The test-specific configuration file test-config.xml makes sure the spring-configured SessionFactory connects with the database configured in Unitils.

<?xml version="1.0" encoding="UTF-8"?>
<beans>
        
        <bean id="dataSource" class="org.unitils.database.UnitilsDataSourceFactoryBean" />

</beans>

When executing the example shown above, following steps are performed sequentially:

  • A spring ApplicationContext instance is created and intialized with services-config.xml
  • The DataSource supplied by the UnitilsDataSourceFactoryBean connects to the unit test database as configured in unitils.properties and unitils-<myproject>-local.properties
  • The userDao spring bean is wired with a SessionFactory that uses the same DataSource underneath
  • The bean named userDao is retrieved from the application context and injected in the userDao field
  • The first test method, testFindUserByLastName, is invoked
  • Using ReflectionAssert the first names of the users are compared with the expected names ignoring the actual order of the list
  • In the second test, assertMappingWithDatabaseConsistent, is invoked. This test checks whether the Hibernate mapping is consistent with the database. This test uses the Hibernate configuration defined in the application context.

The next example shows a test that uses a JPA EntityManager configured using Spring:

@SpringApplicationContext("test-config.xml")
public class UserDaoTest extends UnitilsJUnit4 {
    
    @SpringBean("userDao")
    protected UserDao userDao;
  
    @Test
    public void testFindUserByLastName() {
        List<User> users = userDao.findByLastName("Doe");
        assertPropertyLenientEquals("firstName", Arrays.asList("John", "Jane"), users);
    }
  
    @Test
    public void testMappingWithDatabase() {        
        JpaUnitils.assertMappingWithDatabaseConsistent();
    }
}

The spring configuration files look like the following:

services-config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans>

    <bean id="userDao" class="org.unitils.cookbook.UserDao">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

</beans>        

test-config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans>

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="jpaVendorAdapter">
                <bean class="org.unitils.orm.jpa.util.provider.hibernate.UnitilsHibernateJpaVendorAdapter"/>
        </property>
        <property name="persistenceXmlLocation" value="org/unitils/integrationtest/persistence/jpa/hibernate-persistence-test.xml"/>
    </bean>

        <bean id="dataSource" class="org.unitils.database.UnitilsDataSourceFactoryBean"/>

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>

</beans>        

Note that, if you use hibernate as persistence provider, you have to set the jpaVendorAdaptor property to org.unitils.orm.jpa.util.provider.hibernate.UnitilsHibernateJpaVendorAdapter for your test EntityManager config.

Another tip is to use Spring's @Configuration annotation. It's a new feature in Spring 3.0 and with a little adjustment in your test it's usable with Unitils.
If we have a configuration class called AppConfig, than we can define it like this in our test.

public class SpringWithUnitilsTest extends UnitilsJUnit4  {

    @SpringBeanByType
    private HelloWorld obj;


    @SpringApplicationContext
    public ConfigurableApplicationContext createApplicationContext() {
        return new AnnotationConfigApplicationContext(AppConfig.class);
    }
}