Pre-populating the Database
For many tests of persistence, the database must be put in a particular
state before the test can be run.
For instance, tests of finder methods require some number of
data values to already exist, from which the correct subset
must be selected.
Tests of CRUD operations also require pre-existing values.
Few objects exist without relationships to other objects.
These objects on which the subject of the test depends need to
be created before the main body of the test executes.
Here we show how this problem is addressed in the Case Study.
The method
onSetUpInTransactionAtBeginning
of
AbstractDaoTest
reads in dependencies
and prepopulated objects into local variables, and then
calls methods (
populateDependencies
and
prepopulate
)
that persist those values.
First, notice how objects are prepopulated.
In the Case Study, "prepopulated" means that objects of the type
persisted by the DAO under test are inserted in the database before
the method under test is exercised.
AbstractDaoTest
is a generic class;
objects of type
V
are
Persistable
,
which is merely a layer supertype for all domain model objects
that bestows an identifier property;
objects of type
D
are DAO classes that extend the Case Study's
AbstractDao
class, which
persists objects of generic type
V
.
Given this, we can understand that the
prepopulate method
works by
taking all of the prepopulated objects read from the SpringUnit context
and calling the
create
method of the
DAO of type
D
that is the subject of the test.
AbstractDaoTest.java (excerpt)
public abstract class AbstractDaoTest<V extends Persistable, D extends AbstractDao<V>> extends SpringUnitTransactionalTest {
<-- Note that onSetUpInTransactionAtBeginning is deprecated in SpringUnit 0.6 -->
protected void onSetUpInTransaction() throws Exception {
this.subject = (D)getObject("subject");
this.dependencies = getObject("dependencies");
populateDependencies();
this.prepopulated = (List<? extends V>)getObject("prepopulated");
prepopulate();
}
protected void prepopulate() throws Exception {
if (getPrepopulated() != null && getPrepopulated().size() > 0) {
getSubject().create(getPrepopulated());
}
}
protected List<? extends V> getPrepopulated() {
return this.prepopulated;
}
protected D getSubject() {
return this.subject;
}
private List<? extends V> prepopulated;
private D subject;
protected void populateDependencies() throws Exception {
}
/* other methods and fields omitted */
}
The means of prepopulating the database is common across all types, but
the means of creating object dependencies is type-specific.
For this reason, the method
populateDependencies
does nothing; it must be overriden by descendents.
The next example shows how a subclass,
ProductDaoHibernateTest
,
implements
populateDependencies
.
Product
objects depend on
Category
objects,
so the method reads
"categories"
from the
dependencies
and then calls a
CategoryDao
to create these objects.
ProductDaoHibernateTest.java (excerpt)
protected void populateDependencies() throws Exception {
if (getDependencies() != null && getDependencies().size() > 0) {
List objects = getDependencies().get("categories");
List<? extends Category> categories = (List<? extends Category>)objects;
getCategoryDao().create(categories);
}
}
Note that this behavior is contained in
AbstractDaoTest
,
which is a framework class for the Case Study, but is not a member
of the SpringUnit framework.
Therefore, this pattern of pre-populating objects may be regarded
as a pattern that can be emulated in your tests, but remains
code that you will have to write in your own tests.
Whether this behavior should be elevated to the
SpringUnit framework is an open question.