Abstract
We can take advantage of one of Groovy's features to reduce the boilerplate when writing fixtures. This chapter explains how.
One of the classes provided by the Groovy runtime is
ObjectGraphBuilder
, which (as per its documentation)
is "a builder for an arbitrary graph of beans that follow the JavaBean
convention,... useful for creating test data for example". Which is,
indeed, exactly what we need to do when we create fixtures for use with
the in-memory object store.
The Groovy Objects applib extends this class by
providing the DomainObjectBuilder
, which
additionally ensures that domain objects are instantiated through the
DomainObjectContainer
. The original
ObjectGraphBuilder
also needs to be told explicitly
where the domain object packages are, so
DomainObjectBuilder
makes this easy to do in a
typesafe way.
Let's see it in action. Here's the fixture from the Groovy
Objects testapp, to create 3 Employee
s,
some Claim
s and some
ClaimItem
s within those
Claim
s:
class ClaimsFixture extends AbstractFixture { @Override public void install() { def builder = new DomainObjectBuilder(getContainer(), Employee.class, Claim.class) builder.employee(id: 'fred', name:"Fred Smith") builder.employee(id: "tom", name: "Tom Brown") { approver( refId: 'fred') } builder.employee(name: "Sam Jones") { approver( refId: 'fred') } builder.claim(id: 'tom:1', date: days(-16), description: "Meeting with client") { claimant( refId: 'tom') claimItem( dateIncurred: days(-16), amount: money(38.50), description: "Lunch with client") claimItem( dateIncurred: days(-16), amount: money(16.50), description: "Euston - Mayfair (return)") } builder.claim(id: 'tom:2', date: days(-18), description: "Meeting in city office") { claimant( refId: 'tom') claimItem( dateIncurred: days(-18), amount: money(18.00), description: "Car parking") claimItem( dateIncurred: days(-18), amount: money(26.50), description: "Reading - London (return)") } builder.claim(id: 'fred:1', date: days(-14), description: "Meeting at clients") { claimant( refId: 'fred') claimItem( dateIncurred: days(-14), amount: money(18.00), description: "Car parking") claimItem( dateIncurred: days(-14), amount: money(26.50), description: "Reading - London (return)") } } private Date days(int days) { Date date = new Date(); date = date.add(0,0, days); return date } private Money money(double amount) { return new Money(amount, "USD"); } }
The builder is instantiated by passing in the
DomainObjectContainer
, as well as one
representative class from each package that holds entities to be built. In
this case the Employee.class
takes care of the
employee package (for just
Employee
itself), while
Claim.class
represents the claims
package (for both Claim
and
ClaimItem
).
The DSL for building the object graph is just
that defined by Groovy's ObjectGraphBuilder
. To my
eyes at least, this is easier to follow than its Java equivalent.
There is one limitation to be aware of, though, which relates to how
the Claim
/ClaimItem
parent/child is wired up. It's important for the collection name in the
parent (Claim
) to match that of the class name of
the child (ClaimItem
), and the back reference in
the child (if there is one) to match the class name of the parent. For the
test app, this means that the collection in Claim
is called claimItems
. If this is irksome, then
the ObjectGraphBuilder
does define the ability to
tweak its behaviour as to how the relationship name is inferred. (A future
enhancement to Groovy Objects might be to solve this
problem in the general case, by perform the wiring using the
Naked Objects metamodel).