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 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")});
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:
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); }
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); } }
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>
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.
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.
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
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.
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(); } }
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:
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); } }