I have the following Spring MVC app stack:
Controller -> Service -> DAO (Repository) -> Entity -> MySql InnoDB
Transactions are configured to start from the Service layer using AOP xml config, and the app works perfectly:
<aop:config>
<aop:advisor id="managerTx" advice-ref="txAdvice" pointcut="execution(* *..service.*Service.*(..))" order="1"/>
</aop:config>
<aop:aspectj-autoproxy proxy-target-class="true"/>
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
Now, I am writing Spring MVC tests using spring-mvc-test framework, UnitDB etc. The test class has the following config:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
loader=WebContextLoader.class,
locations={
"classpath:spring/testContext.xml",
"classpath:spring/testDispatcher-servlet.xml",
"classpath:spring/security.xml"
})
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
DbUnitTestExecutionListener.class })
@TransactionConfiguration(transactionManager="transactionManager", defaultRollback=true)
@Transactional(propagation=Propagation.REQUIRED, rollbackFor={Exception.class})
@DatabaseSetup({"classpath:dbunit/initial-data.xml"})
The test looks something like this:
@Test
public void testSomeController() throws Exception {
this.mockMvc.perform(get("/some/controller"));
}
Basically what I want is to test (use) the existing Spring AOP config inside the testing environment, initially setup some DB data, run the tests and rollback everything after the tests are completed.
In the above configuration, the tests are starting their own transaction which in the given propagation config is meeting another transaction at Service layer, started by AOP xml config and I get lock timeout error, because transaction started by test is waiting for the transaction started by AOP config at Service layer.
I am only writing tests and I shouldn't be modifying the actual code, only the test code. My task is to find a way to rollback all changes made by tests with the given configuration.
Any ideas appreciated.
EDIT
Here is the problematic case:
- test class starts one big new transaction with auto-rollback for all tests.
- dbunit fills the db with the initial data
- test launches controller test
- controller makes call to service layer e.g. save/update entity (inserted by DBUnit at the beginning of the test class), new transaction started here at service layer (configured by aop:config) but supported with the big transaction from the step #1
- boom, error happens: Lock wait timeout exceeded; try restarting transaction
I think that the data inserted by DBUnit is still not committed because it is in the same transaction. I need to find a way to insert initial data with DBUnit in a separate transaction but still to roll it back at the end of the test.