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.
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
assertRefEquals(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
assertRefEquals(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
assertRefEquals(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
assertLenEquals(Arrays.asList(new Person("John"), null),
new Person[] {new Person("Jane", "Doe"), new Person("John", "Doe")});
// Check only the firstName property
assertPropertyLenEquals("firstName", Arrays.asList("John", "Jane"),
new Person[] {new Person("Jane", "Doe"), new Person("John", "Doe")});
This example demonstrates the EasyMock and injection modules. The test must extend one of unitils base classes: UnitilsJUnit3, UnitilsJUnit4 or UnitilsTestNG. No additional configuration is needed.
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);
}
}
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 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:
@Transactional(TransactionMode.COMMIT)
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.assertPropertyLenEquals("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>
To enable automatic maintenance of the developers' unit 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 # Set to true if the db version table should be created automatically if it does not exist yet. # If false, an exception is thrown the it does not exist yet, showing how to create the version table manually. # This is set to false by default to be sure that no non-unit test schema is dropped by accident. If a # version table is available, we assume it to be a unit-test schema, if not, you should manually add a version table # to indicate that it is a unit-test schema. dbMaintainer.dbVersionSource.autoCreateVersionTable=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> # Comma separated list of database items that may not be dropped or cleared by the db maintainer when # updating the database from scratch (dbMaintainer.fromScratch.enabled=true). # Schemas can also be preserved as a whole. If identifiers are quoted (eg "" for oracle) they are considered # case sensitive. Items that do not have a schema prefix are considered to be in the default schema dbMaintainer.preserve.schemas= dbMaintainer.preserve.tables= dbMaintainer.preserve.views= dbMaintainer.preserve.synonyms= dbMaintainer.preserve.sequences= # Comma separated list of table names. The tables listed here will not be emptied when the db maintainer performs a database # update. This can be used for Tables that contain rather static, read only or type data. The database version table # is preserved automatically. # Tables listed here will still be dropped when the db maintainer performs a from scratch update. If this is not desirable # you should add the tablename to the dbMaintainer.preserve.tables property instead # Schemas can also be preserved as a whole. If identifiers are quoted (eg "" for oracle) they are considered # case sensitive. Items that do not have a schema prefix are considered to be in the default schema dbMaintainer.preserveDataOnly.schemas= dbMaintainer.preserveDataOnly.tables=
For every time 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: <version>_<some name>.sql . For example:
dbscripts / 001_user_table.sql
002_company_table.sql
Unitils detects that a script was added and will invoke 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.
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 database support is configured correctly as described above and that you have you 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")
@Transactional(TransactionMode.COMMIT)
public class UserDaoTest extends UnitilsJUnit4 {
@PersistenceContext
EntityManager entityManager;
UserDao userDao;
@Before
public void setUp() {
userDao = new UserDao();
userDao.setEntityManager(entityManager);
}
@Test
public void testFindUserByLastName() {
List<User> users = userDao.findByLastName("Doe");
assertPropertyLenEquals("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, respectively.
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.
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")
@Transactional(TransactionMode.COMMIT)
public class HibernateMappingTest extends UnitilsJUnit4 {
@Test
public void testMappingToDatabase() {
JpaUnitils.assertMappingWithDatabaseConsistent();
}
}
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")
@Transactional(TransactionMode.COMMIT)
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");
assertPropertyLenEquals("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.
Note: Since unitils 1.1, tests must always be executed in a transaction.
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")
@Transactional(TransactionMode.COMMIT)
public class HibernateMappingTest extends UnitilsJUnit4 {
@Test
public void testMappingToDatabase() {
HibernateUnitils.assertMappingWithDatabaseConsistent();
}
}
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");
assertPropertyLenEquals("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 specifies the DataSource. The 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:
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");
assertPropertyLenEquals("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.