Announcement Announcement Module
Collapse
No announcement yet.
How to rollback transactions by default with Junit4 tests and tx:advice? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • How to rollback transactions by default with Junit4 tests and tx:advice?

    Hi,

    I was given a library of DAOs that I need to incorporate in my code. In order to wrap the DAOs in a transaction, I have used a tx:advice to wrap all my methods.

    My question now comes with JUnit tests. By default, everything seems to be committing to the DB. I recall using annotation support for transactions in the past, where I could specify @TransactionConfiguration at the Junit4 class level to specify whether or not I wanted my transactions to rollback.

    What is the equivalent of that when using XML configuration?

    ApplicationContext.xml
    Code:
    ...
    <!-- Wrap all DAO Implementations in a transaction -->
    	<aop:config proxy-target-class="false">
    		<aop:pointcut id="daoOperation" expression="execution(* com.calculator.dao.impl.*Impl.* (..))" />
    		<aop:advisor pointcut-ref="daoOperation" advice-ref="txAdvice" />
    	</aop:config>
    
    	<tx:advice id="txAdvice">
    		<tx:attributes>
    			<tx:method name="*" read-only="true" propagation="REQUIRED"/>
    			<tx:method name="execute*" propagation="REQUIRED"/>
    			<tx:method name="query*" propagation="REQUIRED"/>
    			<tx:method name="insert" propagation="REQUIRED"/>
    			<tx:method name="delete" propagation="REQUIRED"/>
    		</tx:attributes>
    	</tx:advice>
    
    				<bean class="org.apache.commons.dbcp.BasicDataSource">
    					<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
    					<property name="url" value="${datasource.url}" />
    					<property name="username" value="${datasource.user}" />
    					<property name="password" value="${datasource.password}" />
    					<property name="defaultAutoCommit" value="false" />
    				</bean>
    
    ...
    Any suggestions would be greatly appreciated.

    Thanks,

    Eric

  • #2
    If you use the spring test classes and configuration then the default is to rollback everything, so please your test classes.

    Comment


    • #3
      Hi,

      I should have pasted my JUnit code as well. This is the first time that I've used the Interceptor as an AOP advice, so I am not sure if I need to do anything special with my JUnits that I don't do when I use annotation based.

      Code:
      @RunWith(SpringJUnit4ClassRunner.class)
      @ContextConfiguration("classpath:spring/applicationContext-TEST.xml")
      public class ApplicationDaoImplSpringTest {
      	@Test
      	public void testInsert() {
      		Long id = new Date().getTime() % 1000000L;
      		Application app = new Application();
      		app.setApplicationcode("CALC");
      		app.setApplicationidentifier(new Long(id));
      		app.setApplicationname("CALCULATOR");
      		applicationDao.insert(app);
      
      		Application app2 = applicationDao.selectByPrimaryKey(new Long(id));
      		Assert.assertTrue(app2.getApplicationname().equalsIgnoreCase("CALCULATOR"));
      	}
      }

      Output (I've only pasted a few lines that I think might be relevant):
      Code:
      2012-02-03 15:46:18,160 DEBUG springframework.test.context.junit4.SpringJUnit4ClassRunner - SpringJUnit4ClassRunner constructor called with [class com.calculator.dao.impl.ApplicationDaoImplSpringTest].
      2012-02-03 15:46:18,209 INFO  org.springframework.test.context.TestContextManager - @TestExecutionListeners is not present for class [class com.calculator.dao.impl.ApplicationDaoImplSpringTest]: using defaults.
      
      .....
      
      2012-02-03 15:46:21,079 DEBUG springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - Autowiring by type from bean name 'com.calculator.dao.impl.ApplicationDaoImplSpringTest' to bean named 'lendingSimulationDaoImpl'
      2012-02-03 15:46:21,082 DEBUG springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'
      2012-02-03 15:46:21,082 DEBUG springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'
      2012-02-03 15:46:21,105 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager - Creating new transaction with name [com.calculator.dao.impl.ApplicationDaoImpl.insert]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
      2012-02-03 15:46:21,466 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager - Acquired Connection [jdbc:oracle:thin:@XXXXXX:1521:XE, UserName=CALOWNER, Oracle JDBC driver] for JDBC transaction
      2012-02-03 15:46:21,490 DEBUG java.sql.Connection - {conn-100000} Connection
      2012-02-03 15:46:21,496 DEBUG java.sql.Connection - {conn-100000} Preparing Statement:      insert into CALOWNER.APPLICATION (APPLICATIONIDENTIFIER, APPLICATIONCODE, APPLICATIONNAME)     values (?, ?, ?)   
      2012-02-03 15:46:21,635 DEBUG java.sql.PreparedStatement - {pstm-100001} Executing Statement:      insert into CALOWNER.APPLICATION (APPLICATIONIDENTIFIER, APPLICATIONCODE, APPLICATIONNAME)     values (?, ?, ?)   
      2012-02-03 15:46:21,636 DEBUG java.sql.PreparedStatement - {pstm-100001} Parameters: [981091, CALC, CALCULATOR]
      2012-02-03 15:46:21,636 DEBUG java.sql.PreparedStatement - {pstm-100001} Types: [java.lang.Long, java.lang.String, java.lang.String]
      2012-02-03 15:46:21,643 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager - Initiating transaction commit
      2012-02-03 15:46:21,643 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager - Committing JDBC transaction on Connection [jdbc:oracle:thin:@XXXXXX:1521:XE, UserName=CALOWNER, Oracle JDBC driver]
      2012-02-03 15:46:21,646 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager - Releasing JDBC Connection [jdbc:oracle:thin:@XXXXXX:1521:XE, UserName=CALOWNER, Oracle JDBC driver] after transaction
      2012-02-03 15:46:21,647 DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource
      2012-02-03 15:46:21,650 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager - Creating new transaction with name [com.calculator.dao.impl.ApplicationDaoImpl.selectByPrimaryKey]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly
      2012-02-03 15:46:21,650 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager - Acquired Connection [jdbc:oracle:thin:@XXXXXX:1521:XE, UserName=CALOWNER, Oracle JDBC driver] for JDBC transaction
      2012-02-03 15:46:21,650 DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Setting JDBC Connection [jdbc:oracle:thin:@XXXXXX:1521:XE, UserName=CALOWNER, Oracle JDBC driver] read-only
      2012-02-03 15:46:21,651 DEBUG java.sql.Connection - {conn-100002} Connection
      2012-02-03 15:46:21,652 DEBUG java.sql.Connection - {conn-100002} Preparing Statement:      select APPLICATIONIDENTIFIER, APPLICATIONCODE, APPLICATIONNAME     from CALOWNER.APPLICATION     where APPLICATIONIDENTIFIER = ?   
      2012-02-03 15:46:21,653 DEBUG java.sql.PreparedStatement - {pstm-100003} Executing Statement:      select APPLICATIONIDENTIFIER, APPLICATIONCODE, APPLICATIONNAME     from CALOWNER.APPLICATION     where APPLICATIONIDENTIFIER = ?   
      2012-02-03 15:46:21,653 DEBUG java.sql.PreparedStatement - {pstm-100003} Parameters: [981091]
      2012-02-03 15:46:21,653 DEBUG java.sql.PreparedStatement - {pstm-100003} Types: [java.lang.Long]
      2012-02-03 15:46:21,678 DEBUG java.sql.ResultSet - {rset-100004} ResultSet
      2012-02-03 15:46:21,694 DEBUG java.sql.ResultSet - {rset-100004} Header: [APPLICATIONIDENTIFIER, APPLICATIONCODE, APPLICATIONNAME]
      2012-02-03 15:46:21,694 DEBUG java.sql.ResultSet - {rset-100004} Result: [981091, CALC, CALCULATOR]
      2012-02-03 15:46:21,698 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager - Initiating transaction commit
      2012-02-03 15:46:21,698 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager - Committing JDBC transaction on Connection [jdbc:oracle:thin:@XXXXXX:1521:XE, UserName=CALOWNER, Oracle JDBC driver]
      2012-02-03 15:46:21,700 DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Resetting read-only flag of JDBC Connection [jdbc:oracle:thin:@XXXXXX:1521:XE, UserName=CALOWNER, Oracle JDBC driver]
      2012-02-03 15:46:21,700 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager - Releasing JDBC Connection [jdbc:oracle:thin:@XXXXXX:1521:XE, UserName=CALOWNER, Oracle JDBC driver] after transaction
      2012-02-03 15:46:21,700 DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource
      2012-02-03 15:46:21,702 DEBUG springframework.test.context.support.DirtiesContextTestExecutionListener - After test method: context [[TestContext@2de12f6d testClass = ApplicationDaoImplSpringTest, locations = array<String>['classpath:spring/applicationContext-TEST.xml'], testInstance = com.calculator.dao.impl.ApplicationDaoImplSpringTest@1af0b4a3, testMethod = testInsert@ApplicationDaoImplSpringTest, testException = [null]]], class dirties context [false], class mode [null], method dirties context [false].
      2012-02-03 15:46:21,703 DEBUG springframework.test.context.support.DirtiesContextTestExecutionListener - After test class: context [[TestContext@2de12f6d testClass = ApplicationDaoImplSpringTest, locations = array<String>['classpath:spring/applicationContext-TEST.xml'], testInstance = [null], testMethod = [null], testException = [null]]], dirtiesContext [false].
      2012-02-03 15:46:21,705 INFO  org.springframework.context.support.GenericApplicationContext - Closing [email protected]0512a: startup date [Fri Feb 03 15:46:19 EST 2012]; root of context hierarchy
      2012-02-03 15:46:21,707 DEBUG springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'lifecycleProcessor'
      2012-02-03 15:46:21,707 INFO  springframework.beans.factory.support.DefaultListableBeanFactory - Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@2f49f041: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,applicationDaoImpl,currencyDaoImpl,errorMessageDaoImpl,frequencyFactorDaoImpl,geographicAreaDaoImpl,geographicSalesTaxDaoImpl,lendingSimulationDaoImpl,mappingMatrixDaoImpl,parameterCriteriaDaoImpl,parameterValueDaoImpl,productConditionDaoImpl,productConditionRltnpDaoImpl,productCriteriaDaoImpl,productDaoImpl,productFrequencyFactorDaoImpl,productPricingDaoImpl,productSalesTaxRltnpDaoImpl,productThresholdDaoImpl,referenceRateDaoImpl,salesTaxRateDaoImpl,uomDaoImpl,valueDaoImpl,valueDomainAppRelationDaoImpl,valueDomainDaoImpl,transactionManager,sqlMapClient,org.springframework.aop.config.internalAutoProxyCreator,daoOperation,org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0,txAdvice,propertyPlaceholder,calculatorDS,simpleNamingContextBuilder,jndi_activate,jndi_dao]; root of factory hierarchy
      2012-02-03 15:46:21,709 DEBUG springframework.beans.factory.support.DefaultListableBeanFactory - Retrieved dependent beans for bean 'lendingSimulationDaoImpl': [com.calculator.dao.impl.ApplicationDaoImplSpringTest]
      2012-02-03 15:46:21,709 DEBUG springframework.beans.factory.support.DefaultListableBeanFactory - Retrieved dependent beans for bean '(inner bean)': [txAdvice]
      2012-02-03 15:46:21,709 DEBUG springframework.beans.factory.support.DefaultListableBeanFactory - Retrieved dependent beans for bean 'org.apache.commons.dbcp.BasicDataSource#21bbd3e2': [jndi_dao]

      As you can see, there is no rollback at the end of the test. Am I missing something? Must my JUnit class be structured differently to use the XML advisor instead of annotation-based?

      Thanks,

      Eric

      Comment


      • #4
        Put @Transactional on your testcase and inject the entitymanager, after your insert you need to flush the entitymanager (to similate a transaction). Als in general if you want to check the state you shouldn't use persistence solution used, but plain JDBC. So I suggest extending AbstractTransactionalJUnit4SpringContextTest which gives you transactional support out of the box and a simpleJdbcTemplate to execute queries on the current connection so you can do counts and check if it is really flushed to the database.

        Comment

        Working...
        X