Results 1 to 4 of 4

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

  1. #1

    Default 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. #2
    Join Date
    Jun 2006
    Location
    The Netherlands
    Posts
    13,695

    Default

    If you use the spring test classes and configuration then the default is to rollback everything, so please your test classes.
    Marten Deinum
    Java Consultant / Pragmatist / Open Source Enthousiast / Author


    Pro Spring MVC: With Web Flow
    Conspect

    Have you read the reference guide.
    Use the [ code ] tags, young padawan

  3. #3

    Default

    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 org.springframework.context.support.GenericApplicationContext@23e0512a: 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

  4. #4
    Join Date
    Jun 2006
    Location
    The Netherlands
    Posts
    13,695

    Default

    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.
    Marten Deinum
    Java Consultant / Pragmatist / Open Source Enthousiast / Author


    Pro Spring MVC: With Web Flow
    Conspect

    Have you read the reference guide.
    Use the [ code ] tags, young padawan

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •