Spring does not provide a class such as AbstractTransactionalDataSourceSpringContextTests that extends from the MockStrutsTestCase. This might be due to practical issues with the way Spring context initialization works when using MockStrutsTestCase. I tried achieving the transaction rollback in the same way as was done in the AbstractTransactionalDataSourceSpringContextTests class but it didn't work out as the application code started a new transaction and commited as usual without using the transaction I started in my own subclass of MockStrutsTestCase.
Another option left for me was to go down to the Transaction Manager level and achieve the rollbacks there. The application uses Hibernate at the DAO level and it was using HibernateTransactionManager as the transaction manager implementation when running test cases . Therefore I had to write a new class extending from HibernateTransactionManager which overrides the doCommit() method. The overridden method will call doRollback() method in the super class. This would rollback the current running transaction even if the declarative transaction handling code in Spring calls doCommit on the transaction manager.
package com.xyz.txn;
import org.springframework.orm.hibernate3.HibernateTransactionManager;
public class HibernateRollbackTxnManager extends HibernateTransactionManager {
/*
* doCommit method that calls the doRollback method of the super class.
*
*/
protected void doCommit(DefaultTransactionStatus txnStatus) {
super.doRollback(txnStatus);
}
}
Finally override the default transaction manager in your test spring bean configuration with the rollback only implementation.
<bean id="txnManager" class="com.com.xyz.txn.HibernateRollbackTxnManager">
<property name="sessionFactory"><ref local="sessionFactory"></property>
</bean>
The same strategy would work with other transaction managers such as DataSourceTransactionManager too.
6 comments:
I did try it, But no rollback is done at the end of the transaction.
don't know if there is some configuration to be done except what is in the content of the article.
I'm assuming you already have configured your service beans that are accessed by the action classes to be transactional.
Also make sure there are no other transaction managers configured in your spring files with a different name/id.
Finally add a System.out statement in the doCommit method to make sure Spring is using the HibernateRollbackTxnManager and calling it's doCommit method.
It is working now!
I had some transaction configuration issue
Thanks
Bull shit, man! You can acheve it without any custom transaction managers! Just extend you tests from the AbstractTransactional...Test and delegate processing of the requests to the struts mock container (StrutsTestCase).
I tried it but I am facing the following exception.
servletunit.struts.ExceptionDuringTestError: An uncaught exception was thrown during actionExecute()
at servletunit.struts.MockStrutsTestCase.actionPerform(MockStrutsTestCase.java:409)
at com.nms.test.webapp.methodology.MilestoneListActionTest.executeAction(MilestoneListActionTest.java:35)
at com.nms.test.webapp.methodology.MilestoneListActionTest.testMilestoneList_submit(MilestoneListActionTest.java:56)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
------------
Root Cause:
------------
javax.servlet.ServletException: java.lang.IllegalStateException: Cannot deactivate transaction synchronization - not active
at org.apache.struts.action.RequestProcessor.processException(RequestProcessor.java:545)
at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:486)
at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:274)
at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1482)
at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:525)
at servletunit.struts.MockStrutsTestCase.actionPerform(MockStrutsTestCase.java:394)
at com.nms.test.webapp.methodology.MilestoneListActionTest.executeAction(MilestoneListActionTest.java:35)
at com.nms.test.webapp.methodology.MilestoneListActionTest.testMilestoneList_submit(MilestoneListActionTest.java:56)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
.
.
.
.
Sorry, I was doing some mistake. I have cleared that and now it's working fine for me.
Post a Comment