Java Reference
In-Depth Information
developed in parallel, by different teams. Using this approach, the whole business
layer could be developed and unit tested without depending on the persistence
layer, which would free the business developers from database worries. It's still nec-
essary to test everything together though, but that could be achieved through inte-
gration tests. A good compromise is to write many small (and fast) unit tests that
extensively exercise individual components and then a few (and slower) integra-
tion tests that cover the most important scenarios.
Similarly, we could test the persistence layer using mocks for the
JPA
interfaces. But
this approach isn't recommended, because mocks only emulate
API
calls, and that
wouldn't be enough, for a few reasons. First, the
API
is part of
JPA
-based development;
it's still necessary to annotate classes and provide configuration files. Second, even if
the
JPA
part is correctly configured, there are still third parties involved: the
JPA
ven-
dor (like Hibernate), the vendor's driver (such as
HibernateDialect
implementa-
tions) for the database being used, not to the mention the database itself. Many things
could go wrong (like vendor or drivers bugs, the use of table names that are illegal for
a given database, transaction issues, and the like) at runtime that wouldn't be
detected by using mocks for testing.
Who let the transactions out?
In a JPA-based application, it's paramount to start and commit transactions, and
the methods that use an
EntityManager
have two options: either they handle the
transactions themselves, or they rely on the upper layers for this dirty job. Typical-
ly, the latter option is more appropriate, because it gives the caller the option to
invoke more than one DAO method in the same transaction. Looking at our exam-
ples,
UserDaoJpaImpl
follows this approach, because it doesn't deal with transac-
tion management. But if you look at its caller,
UserFacadeImpl
, it doesn't handle
transactions either! So, in our application example, who is responsible for transac-
tion management?
The answer is the container. In our examples, we're showing pieces of an applica-
tion. But in a real project, these pieces would be assembled by a container, like a
Java EE application server or Spring, and this container would be responsible for
wrapping the
Facade
methods inside a JPA transaction and propagating it to the
DAO object. In our DAO test cases, we play the role of the container and explicitly
manage the transactions.
For the persistence layer, it's important to test real access to the database, as we dem-
onstrate in the next section.
18.2
Aspects of JPA testing
When you use
JPA
(or any other
ORM
software) in your application, you're delegating
the task of persisting objects to and from the database to an external tool. But in the
end, the results are the same as if you wrote the persistence code yourself. So, in its