Thursday, March 15, 2012

Running Integration Tests Across Transaction Boundaries

The normal way to run an integration test that manipulates data in a database is of course a transactional test class backed by Spring's SpringJUnit4ClassRunner. In most instances this works great. However, what happens if the the code under test spans transaction boundaries? Say, due to an @Transaction(propagation = Propagation.REQUIRES_NEW) declaration? As you'd expect, a new transaction is created that is independent of the transaction created by the test class. Fortunately, if you dig deep enough, it turns out there's a surprisingly simple solution. Get a handle on the application context using whatever means you'd like, extract the TransactionInterceptor, and swap out its TransactionAttributeSource. TransactionAttributeSource is responsible for detecting the @Transactional annotations on classes and methods. MatchAlwaysTransactionAttributeSource is a built-in implementation that doesn't even bother to look. It ignores any annotations, and just returns the default transaction configuration. Now, the entire test will run within a single transaction.