Take advantage of an out-of-the-box integration test support to write your own custom integration tests for the database of your choice using the standard integration test infrastructure.
Having a generic DAO pattern implementation with all of its handy features is nice, but how can one be sure that it works properly for a specific database? This is actually a quite important aspect since developers using DAO Fusion need to feel "safe" when using the out-of-the-box DAO functionality. The basic idea behind the integration test support is to encourage developers to use DAO Fusion, given that:
An integration test is basically a unit test interacting with the database instance via JPA / Hibernate, employing a default method-level rollback strategy which ensures proper test data separation between multiple test runs. DAO Fusion achieves this using JUnit and Spring TestContext framework in a consistent integration test infrastructure.
There are basically two kinds of integration tests:
DAO Fusion is currently integration-tested against following databases:
This means that DAO Fusion includes standard integration tests for databases listed above as part of its unit tests within the daofusion-test project. You are free to check out the daofusion-test project from the source code repository and run these tests by yourself. This is, however, not quite necessary since our continuous integration system performs this task when building DAO Fusion automatically.
To sum it up, standard core integration tests need not to be run manually - the daofusion-test project is intended for use as a test-scoped library, providing the integration test infrastructure for custom integration tests.
BaseHibernateIntegrationTest represents a generic integration test which is agnostic of the underlying database instance in use. BaseHibernateIntegrationTest uses the SpringJUnit4ClassRunner which provides the functionality of Spring TestContext framework to standard JUnit tests. BaseHibernateIntegrationTest declares two test execution listeners vital for integration tests (DependencyInjectionTestExecutionListener and TransactionalTestExecutionListener) along with the default method-level rollback strategy via the TransactionConfiguration annotation.
BaseHibernateIntegrationTest defines its own parent Spring context for all integration tests. This context contains everything necessary to set up the basic JPA / Hibernate test environment, including the following components:
In order to make specific integration tests work properly, some additional configuration steps need to be performed:
BaseHibernateIntegrationTest introduces a test profile convention for running fine-grained integration tests against local / remote databases. Assume that your application includes several custom integration tests for local and remote databases: a local database installed on developer's machine and a remote database reachable from the company's continuous integration system. It's convenient for the developer to run integration tests locally before commiting his changes. On the other hand, the continuous integration system can run integration tests against the remote database dedicated for this purpose. The general rule of thumb is to have local / remote databases of the same kind as "real" production ones. See the BaseHibernateIntegrationTest Javadoc for more information about the test profile convention as well as other useful hints.
BaseHibernateCoreIntegrationTest is an extension of the BaseHibernateIntegrationTest for core integration tests aimed at standard persistent entity DAO implementations. Core integration tests operate on the sample eShop domain model defined within the example subpackage. This domain model includes persistent entity and enumeration classes as well as corresponding DAO implementations. BaseHibernateCoreIntegrationTest is actually a base class for core integration tests - all of the configuration details mentioned above still applies to its subclasses. The main purpose of BaseHibernateCoreIntegrationTest is to inject eShop DAO dependencies as well as preparing initial test data to be shared by all test cases.
There are two abstract core integration test classes derived from BaseHibernateCoreIntegrationTest which correspond to standard DAO implementations: AbstractHibernateEntityDaoTest and AbstractHibernateEnumerationDaoTest. These classes contain the actual test code working with sample DAO implementations. Since they are abstract, the user needs to extend and configure them for a specific database instance.
As for custom generic integration tests aimed at testing business-related DAO functionality, you should extend the BaseHibernateIntegrationTest directly and provide all the configuration details regarding target database instance(s). The best way to start writing such integration tests is to examine the integration test infrastructure and the way how standard core integration tests use it in detail.
Assuming that you follow the general multi-tier client-server architecture within your application, there are a couple of things that set the DAO and service layers apart from each other:
Note that the service layer doesn't need integration tests, assuming the DAO layer itself is integration-tested. A service is, after all, just using the DAO to perform complex business operations. It's generally recommended to follow the mock object approach for unit-testing the service layer in a way that abstracts from the underlying data access and puts focus to the actual business problem.
So, you have your favorite database for which you want to test the core DAO functionality using the standard integration test infrastructure. First thing you need to do is to extend AbstractHibernateEntityDaoTest / AbstractHibernateEnumerationDaoTest like this (we use PostgreSQL in this case):
@ContextConfiguration(locations = { DatabaseContextLocations.POSTGRESQL }) @IfProfileValue(name = BaseHibernateIntegrationTest.PROFILE_DBTYPE_NAME, values = { BaseHibernateIntegrationTest.PROFILE_DBTYPE_VALUE_ALL, BaseHibernateIntegrationTest.PROFILE_DBTYPE_VALUE_LOCAL }) public class PostgreSQLHibernateEntityDaoTest extends AbstractHibernateEntityDaoTest { // standard test methods inherited from the parent }
DatabaseContextLocations.POSTGRESQL should point to a Spring context for a local PostgreSQL database instance:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <!-- bean property value resolution --> <context:property-override location="classpath:postgresql/test-postgresql-beanSetup.properties" /> </beans>
The test-postgresql-beanSetup.properties file referenced by this context would look like this:
# pooled JDBC data source configuration dataSource.driverClass=org.postgresql.Driver dataSource.jdbcUrl=jdbc:postgresql://localhost:5432/postgres dataSource.user=postgres dataSource.password=postgres # name of the integration test persistence unit entityManagerFactory.persistenceUnitName=dao-test-postgresql
Since JPA uses META-INF/persistence.xml as the default persistence metadata descriptor, you need to provide this file as well:
<?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0"> <persistence-unit name="dao-test-postgresql" transaction-type="RESOURCE_LOCAL"> <mapping-file>test-core-orm.xml</mapping-file> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" /> </properties> </persistence-unit> </persistence>
How cool is that? Using the standard integration test infrastructure that takes care of the JPA / Hibernate test environment, we are able to write custom core integration tests with only a few lines of Java code and configuration. Notice that we're using the test-core-orm.xml file defining entity mappings for the sample eShop domain model.