@Transaction Around Test
Author
Marcus HeldHi,
My fingers were tingling at the start of Thorben Janssen’s session “The Big Java Persistence Q&A”.
The first question was roughly:
“In the previous talk (something with JPA), it was said that one should annotate every test with
@Transactional
. This will automatically roll back the data after the test. We’ve had a discussion and can’t agree. What’s your recommendation?”
Thorben’s answer made me nervous. He countered with a question of his own, also paraphrased:
“Is your production code within a transaction? Likely it is. That’s why you should also use a transaction in your test.”
So the message is: Yes. Please use @Transactional
.
I got really nervous about the recommendation. I’ve seen this concept fail so often.
Here are my reasons:
- A Test is a Client : It should invoke the production code as a real client would. It is unlikely that the entire test - including assertions - is within a transaction.
- The Encompassing Persistence Context Could Change My Results :
- Perhaps the database has written into a field through a trigger.
- Or I might open several transactions in my application code, which wouldn’t be emulated by an overarching transaction.
- Unmanaged entities could be passed around between different persistence contexts, potentially leading to errors in production.
I simply do not want a transaction around the test by default. I talked about this back in 2020 in my talk (k)lean JPA .
After the talk, I discussed it with Thorben and the questioner. And the rationale was solid. Thorben gave examples of both situations where you would and wouldn’t want that.
It’s as Always - It Depends.
But we were in agreement. There should be no transaction by default.
JPA is complex. Only when you’ve understood the basics do the errors and behaviors you observe start to make sense. And the basics are not so trivial.
Have you actually read the JPA Standard ? No? Then you definitely should catch up!
And check out my talk on (k)lean JPA . Even though it was initially focused on Kotlin: all the issues I address, you also encounter with Java.
Some you may experience less often. Java has different defaults. For instance, all classes in Java are open
by default, not final
. So you probably haven’t experienced lazy fetching not working for “inexplicable reasons”.
What do you think about using @Transactional
in tests? Have you given it some thought? Feel free to write to me!
P.S.: Thorben is a terrific guy and knows his stuff. If you’d rather not read the JPA Standard and need training, get in touch with him !
P.P.S.: I presented “The Performance Mindset” at W-JAX last week . For those who’ve joined us since then. Welcome! If you missed it, you can watch the English version I delivered as a keynote at the RabbitMQ Summit on YouTube .
Rule the Backend,
~ Marcus