Basic problem: I've been trying to find it, but I don't see a callback-based
approach to explicit transaction demarcation that I can use in my tests.
Most of the existing test code suggests that the "right" way to make part of a
test method transactional is to have an EntityManagerFactory nearby and to structure the
test method like this:
@Test
| public void testMethod() throws Exception {
|
| (non-transactional code here)
|
| EntityManager em = getEntityManagerFactory().createEntityManager();
| em.getTransaction().begin();
|
| (transactional code here)
|
| em.getTransaction.commit();
| em.close();
|
| (non-transactional code here)
|
| }
Which works okay, if you don't mind your test code directly interacting with the
EntityManagerFactory, EntityManager and the Transaction; and if you're testing
non-failure cases; and if the test passes without any problem...
Some of those issues might lead you to write slightly safer transactional code, which
might look like this:
@Test
| public void testMethod() throws Exception {
|
| (non-transactional code here)
|
| EntityManager em = getEntityManagerFactory().createEntityManager();
| try {
| em.getTransaction().begin();
|
| (transactional code here)
|
| em.getTransaction().commit();
| } catch (Exception e) {
| em.getTransaction().rollback();
| throw e;
| } finally {
| em.close();
| }
|
| (non-transactional code here)
|
| }
I'm sure that a lot of us have seen transactional boilerplate like that, however,
there are better ways to solve this problem. This is what I really want my test method to
look like:
@Test
| public void testMethod() throws Exception {
|
| (non-transactional code here)
|
| getTransactionManager().execute(new TransactionCallback() {
| public void doInTransaction() {
|
| (transactional code here)
|
| }
| });
|
| (non-transactional code here)
|
| }
Which eliminates all of the problems with the initial approach with a lot less boilerplate
than the second approach, lets me focus the test on exercising my code instead of managing
the EntityManager (or Session, or whatever), lets me use the exact same transaction
manager in testing as in production, and with a few further refinements, can give me full
access to different transaction semantics (REQUIRES_NEW, ALLOWS, etc.) if I need them.
So, my question is: did I miss the part of the documentation where Seam supports some
means of using transactional callbacks for explicit management of transactional code or
should I spend a couple of days and adapt one of my pre-Spring, SLSB-based frameworks to
do this in EJB3 and Java5?
I must admit, that as long as this pattern has been around, I'm a little astonished
that I don't see documentation for something like it in Seam re: transactions or if
I'm just unable to read the docs: that the testing examples don't use it.
I've been using transactional callbacks to insulate developers from transaction
complexity since I first used Hibernate back in the 1.x days (2002) and I didn't
invent it back then. Spring's TransactionManager provides a similar implementation
for explicit demarcation (my example is pretty much "the Spring way"), but the
pattern was around long before Spring appeared on the scene.
One other possibility is to bring Spring into my app and use Spring's
TransactionManager for explicit and AOP-implemented transactions. Upside: I could get rid
of a LOT of SLSB's that are only doing duty as transaction markers now. Upside: when
I don't need true JTA transactions (which is never in this app), I don't have to
worry about them. Downside: yet another external dependency. Downside: two different IOC
controllers to configure properly. Neither up nor down: if I'm bringing in Spring for
transactions, I might as well bring Spring WebFlow to handle conversational scoped beans
and then I'm running out of responsibilities to justify the weight of JBoss/Seam...
Thoughts?
Ross
View the original post :
http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4032282#...
Reply to the post :
http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&a...