Java Reference
In-Depth Information
Back to our test cases, the dataset files contain references to the
ID
columns (both
as primary key in the users table and foreign key on telephones), and because we're
using the same dataset for both load and save, the
ID
values must be defined dynami-
cally at the time the test is run. If we used distinct datasets, the
ID
s wouldn't matter on
the load test (because
JPA
wouldn't be persisting entities, only loading them), and for
the save tests, we could ignore them. The problem with this option is that it makes it
harder to write and maintain the test cases. It would require two datasets and also
changes in the
DataSetsTemplateRunner.assertDataSet()
method in order to
ignore the
ID
columns. Because our goal is always to facilitate long-term maintenance,
we opted for using the same dataset, and hence we need a solution for the
ID
synchro-
nization problem.
Listing 18.10 tried to solve the problem the simplest way, by letting the test case
update the
ID
s, but that approach had many issues. A better approach is to integrate
the dataset
ID
's maintenance with the
JPA
's entity
ID
's generation, and there are two
ways to achieve such integration: taking control of
ID
generation or being notified of
the generated
ID
s.
Generating
ID
s for persistent objects isn't a simple task, because there are many
complex aspects to be taken into account, such as concurrent
ID
generation in dif-
ferent transactions. Besides, when you use this approach, your test cases won't be
reflecting the real application scenario (and hence they could hide potential prob-
lems). For these reasons, we choose the second approach: being notified of the gen-
erated
ID
s.
Using pure
JPA
, it's possible to define a listener for entity lifecycle events (like
object creation, update, and deletion). But this approach doesn't work well in our
case, because these events don't provide a clear way to obtain the
ID
of the saved
objects. A better solution is to use vendor-specific extensions.
Hibernate provides its own
API
for lifecycle events, with listeners for many pre and
post events. In particular, it provides a
PostInsertEventListener
interface with an
onPostInsert(PostInsertEvent
event)
method, and the event itself contains a refer-
ence to both the entity inserted and the generated
ID
.
The
PostInsertEventListener
API
solves part of our problem: our test cases
now can be notified of the
ID
s generated for each object. Good, but now what? Well,
the answer relies on our good, old friend
EL
(Expression Language, introduced in
chapter 17, section 17.7.3). So far, we've been using simple variable resolution (like
${id}
) on our datasets. But
EL
also supports function resolution, so we could have a
function that returns an
ID
for a given class and then use a
PostInsertEvent-
Listener
to set the values returned by the function. Let's start with the new dataset,
shown in listing 18.11.
Listing 18.11
New version of user-with-telephone.xml dataset, using EL functions
<dataset>
<users id="${db:id('User')}" username="ElDuderino"
first_name="Jeffrey" last_name="Lebowsky" />