Title: Testing Transactions Example
# Overview
Testing an EntityManager that uses the default,
PersistenceContextType.TRANSACTION, can be challenging due to Entities
detaching around transaction boundaries. If you were to take the [Injection of EntityManager Example](injection-of-entitymanager-example.html)
which uses an EXTENDED persistence context and switch it to a TRANSACTION
persistence context making no other changes, you'd find that the test would
fail. This would be because of the detach.
Generally, when using an EntityManager with TRANSACTION persistence
context, your transaction should surround your use of the Entities
themselves, not just the use of the EntityManager. Using a [transaction in your unit test](unit-testing-transactions.html)
can make testing these scenarios possible.
This example shows use of @PersistenceContext to have an *EntityManager*
with an *TRANSACTION* persistence context injected into a *@Stateful* bean
using the *@TransactionAttribute* annotation and a TestCase that runs test
code in a JTA *Transaction*. An EJB 3 @Entity bean is used with the
EntityManager to create, persist and merge data to a database.
_The source for this example is in the "testing-transactions" directory
located in the [openejb-examples.zip](openejb:download.html)
available on the download page._
# The Code
{snippet:id=code|url=openejb3/examples/testing-transactions/src/main/java/org/superbiz/injection/tx/MoviesImpl.java|lang=java}
In the above bean code we see that the transaction attribute for all method
of the bean has been changed the default, which is
TransactionAttributeType.REQUIRED, to TransactionAttributeType.MANDATORY.
The MANDATORY transaction attribute is similar to REQUIRED in that the bean
method is guaranteed to be executed in a transaction, but with the added
restriction that if a transaction isn't started by the client before
calling the method, an exception will be thrown.
The benefit of MANDATORY in this example is that it is impossible for the
client to get detached Entity issues. The client either has a transaction
and therefore gets Entities which are still attached and persistent, or the
client would get an exception stating that the use of a transaction is
mandatory.
See the [Transaction Annotations](transaction-annotations.html)
page for a full description of the available transaction attributes.
# Writing a unit test for the example
The magic in the TestCase below is the *TransactionBean* @Stateless bean
which is tucked away as an inner class of the TestCase itself. With this
bean, we can call our test code within the scope of a container controlled
transaction. This allows our test code to use the EntityManager and the
Entities in the scope of a transaction, avoid any detach issues and
satisfying the TransactionAttributeType.MANDATORY requirement of our
MoviesImpl @Stateful bean.
{snippet:id=code|url=openejb3/examples/testing-transactions/src/test/java/org/superbiz/injection/tx/MoviesTest.java|lang=java}
Curious on the InitialContext parameters used? See the [Injection of DataSource Example](injection-of-datasource-example.html)
for an explanation of how any Resource can be configured via properties in
the TestCase itself or via an openejb.xml file.
# Running
Running the example is fairly simple. In the "testing-transactions"
directory of the [examples zip](openejb:download.html)
, just run:
$ mvn clean install
Which should create output like the following.
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running org.superbiz.injection.tx.MoviesTest
Apache OpenEJB 3.0 build: 20080408-04:13
http://openejb.apache.org/
INFO - openejb.home =
/Users/dblevins/work/openejb-3.0/examples/testing-transactions
INFO - openejb.base =
/Users/dblevins/work/openejb-3.0/examples/testing-transactions
INFO - Configuring Service(id=Default Security Service,
type=SecurityService, provider-id=Default Security Service)
INFO - Configuring Service(id=Default Transaction Manager,
type=TransactionManager, provider-id=Default Transaction Manager)
INFO - Configuring Service(id=movieDatabaseUnmanaged, type=Resource,
provider-id=Default JDBC Database)
INFO - Configuring Service(id=movieDatabase, type=Resource,
provider-id=Default JDBC Database)
INFO - Configuring Service(id=Default JDK 1.3 ProxyFactory,
type=ProxyFactory, provider-id=Default JDK 1.3 ProxyFactory)
INFO - Found EjbModule in classpath:
/Users/dblevins/work/openejb-3.0/examples/testing-transactions/target/test-classes
INFO - Found EjbModule in classpath:
/Users/dblevins/work/openejb-3.0/examples/testing-transactions/target/classes
INFO - Configuring app:
/Users/dblevins/work/openejb-3.0/examples/testing-transactions/target/test-classes
INFO - Configuring Service(id=Default Stateless Container, type=Container,
provider-id=Default Stateless Container)
INFO - Auto-creating a container for bean TransactionBean:
Container(type=STATELESS, id=Default Stateless Container)
INFO - Loaded Module:
/Users/dblevins/work/openejb-3.0/examples/testing-transactions/target/test-classes
INFO - Configuring app:
/Users/dblevins/work/openejb-3.0/examples/testing-transactions/target/classes
INFO - Configuring Service(id=Default Stateful Container, type=Container,
provider-id=Default Stateful Container)
INFO - Auto-creating a container for bean Movies: Container(type=STATEFUL,
id=Default Stateful Container)
INFO - Configuring PersistenceUnit(name=movie-unit)
INFO - Loaded Module:
/Users/dblevins/work/openejb-3.0/examples/testing-transactions/target/classes
INFO - Assembling app:
/Users/dblevins/work/openejb-3.0/examples/testing-transactions/target/test-classes
INFO - Jndi(name=TransactionBeanLocal) -->
Ejb(deployment-id=TransactionBean)
INFO - Created Ejb(deployment-id=TransactionBean, ejb-name=TransactionBean,
container=Default Stateless Container)
INFO - Deployed
Application(path=/Users/dblevins/work/openejb-3.0/examples/testing-transactions/target/test-classes)
INFO - Assembling app:
/Users/dblevins/work/openejb-3.0/examples/testing-transactions/target/classes
INFO - PersistenceUnit(name=movie-unit,
provider=org.apache.openjpa.persistence.PersistenceProviderImpl)
ERROR - JAVA AGENT NOT INSTALLED. The JPA Persistence Provider requested
installation of a ClassFileTransformer which
requires a JavaAgent. See
http://openejb.apache.org/3.0/javaagent.html
INFO - Jndi(name=MoviesLocal) --> Ejb(deployment-id=Movies)
INFO - Created Ejb(deployment-id=Movies, ejb-name=Movies, container=Default
Stateful Container)
INFO - Deployed
Application(path=/Users/dblevins/work/openejb-3.0/examples/testing-transactions/target/classes)
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.25 sec
Results :
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0