Support @Rollback on classes & deprecate @TxConfig

Since Spring Framework 2.5, @Rollback has been supported on test
methods, with class-level rollback settings configured via
@TransactionConfiguration; however, allowing @Rollback to be declared
on test classes with method-level declarations overriding class-level
declarations would prove more intuitive than having to declare both
@TransactionConfiguration and @Rollback. Furthermore, the
transactionManager flag in @TransactionConfiguration was made
superfluous many years ago with the introduction of support for a
qualifier in @Transactional.

This commit enables @Rollback to be declared at the class level for
default rollback semantics within test class hierarchies and deprecates
@TransactionConfiguration in favor of @Rollback and @Transactional
qualifiers.

Issue: SPR-13276, SPR-13277
This commit is contained in:
Sam Brannen 2015-07-25 18:22:26 +02:00
parent efd7f9bf72
commit 3f8b51283e
22 changed files with 713 additions and 196 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -24,25 +24,36 @@ import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
/**
* Test annotation used to indicate whether or not the transaction for the
* annotated test method should be <em>rolled back</em> after the test method
* has completed. If {@code true}, the transaction will be rolled back;
* otherwise, the transaction will be committed.
* Test annotation used to indicate whether a <em>test-managed transaction</em>
* should be <em>rolled back</em> after the test method has completed.
*
* <p>Consult the class-level Javadoc for
* {@link org.springframework.test.context.transaction.TransactionalTestExecutionListener}
* for an explanation of <em>test-managed transactions</em>.
*
* <p>When declared as a class-level annotation, {@code @Rollback} defines
* the default rollback semantics for all test methods within the test class
* hierarchy. When declared as a method-level annotation, {@code @Rollback}
* defines rollback semantics for the specific test method, potentially
* overriding class-level default rollback semantics.
*
* <p>As of Spring Framework 4.0, this annotation may be used as a
* <em>meta-annotation</em> to create custom <em>composed annotations</em>.
*
* @author Sam Brannen
* @since 2.5
* @see org.springframework.test.context.transaction.TransactionalTestExecutionListener
*/
@Documented
@Retention(RUNTIME)
@Target({ METHOD, ANNOTATION_TYPE })
@Target({ TYPE, METHOD, ANNOTATION_TYPE })
public @interface Rollback {
/**
* Whether or not the transaction for the annotated method should be rolled
* back after the method has completed.
* Whether the <em>test-managed transaction</em> should be rolled back
* after the test method has completed.
* <p>If {@code true}, the transaction will be rolled back; otherwise,
* the transaction will be committed.
*/
boolean value() default true;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -36,8 +36,8 @@ import org.springframework.util.StringUtils;
/**
* Utility methods for working with transactions and data access related beans
* within the <em>Spring TestContext Framework</em>. Mainly for internal use
* within the framework.
* within the <em>Spring TestContext Framework</em>.
* <p>Mainly for internal use within the framework.
*
* @author Sam Brannen
* @author Juergen Hoeller
@ -146,6 +146,8 @@ public abstract class TestContextTransactionUtils {
* @return the transaction manager to use, or {@code null} if not found
* @throws BeansException if an error occurs while retrieving an explicitly
* named transaction manager
* @throws IllegalStateException if more than one TransactionManagementConfigurer
* exists in the ApplicationContext
*/
public static PlatformTransactionManager retrieveTransactionManager(TestContext testContext, String name) {
Assert.notNull(testContext, "TestContext must not be null");

View File

@ -39,7 +39,10 @@ import java.lang.annotation.Target;
* @see org.springframework.test.context.jdbc.SqlConfig
* @see org.springframework.test.context.jdbc.SqlConfig#transactionManager
* @see org.springframework.test.context.ContextConfiguration
* @deprecated As of Spring Framework 4.2, use {@code @Rollback} at the class
* level and the {@code transactionManager} qualifier in {@code @Transactional}.
*/
@Deprecated
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@ -48,7 +51,7 @@ public @interface TransactionConfiguration {
/**
* The bean name of the {@link org.springframework.transaction.PlatformTransactionManager
* PlatformTransactionManager} that should be used to drive transactions.
* PlatformTransactionManager} that should be used to drive <em>test-managed transactions</em>.
*
* <p>The name is only used if there is more than one bean of type
* {@code PlatformTransactionManager} in the test's {@code ApplicationContext}.
@ -76,7 +79,7 @@ public @interface TransactionConfiguration {
String transactionManager() default "";
/**
* Should transactions be rolled back by default?
* Whether <em>test-managed transactions</em> should be rolled back by default.
*/
boolean defaultRollback() default true;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -36,14 +36,27 @@ public class TransactionConfigurationAttributes {
/**
* Construct a new TransactionConfigurationAttributes instance from the
* supplied arguments.
* Construct a new {@code TransactionConfigurationAttributes} instance
* using an empty string for the bean name of the
* {@link PlatformTransactionManager} and {@code true} for the default
* rollback flag.
* @see #TransactionConfigurationAttributes(String, boolean)
*/
public TransactionConfigurationAttributes() {
this("", true);
}
/**
* Construct a new {@code TransactionConfigurationAttributes} instance
* from the supplied arguments.
* @param transactionManagerName the bean name of the
* {@link PlatformTransactionManager} that is to be used to drive transactions
* @param defaultRollback whether or not transactions should be rolled back by default
* {@link PlatformTransactionManager} that is to be used to drive
* <em>test-managed transactions</em>
* @param defaultRollback whether or not <em>test-managed transactions</em>
* should be rolled back by default
*/
public TransactionConfigurationAttributes(String transactionManagerName, boolean defaultRollback) {
Assert.notNull(transactionManagerName, "transactionManagerName can not be null");
Assert.notNull(transactionManagerName, "transactionManagerName must not be null");
this.transactionManagerName = transactionManagerName;
this.defaultRollback = defaultRollback;
}
@ -51,14 +64,14 @@ public class TransactionConfigurationAttributes {
/**
* Get the bean name of the {@link PlatformTransactionManager} that is to
* be used to drive transactions.
* be used to drive <em>test-managed transactions</em>.
*/
public final String getTransactionManagerName() {
return this.transactionManagerName;
}
/**
* Whether or not transactions should be rolled back by default.
* Whether <em>test-managed transactions</em> should be rolled back by default.
* @return the <em>default rollback</em> flag
*/
public final boolean isDefaultRollback() {

View File

@ -30,7 +30,6 @@ import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.support.AbstractTestExecutionListener;
@ -84,9 +83,8 @@ import static org.springframework.core.annotation.AnnotationUtils.*;
* <h3>Declarative Rollback and Commit Behavior</h3>
* <p>By default, test transactions will be automatically <em>rolled back</em>
* after completion of the test; however, transactional commit and rollback
* behavior can be configured declaratively via the class-level
* {@link TransactionConfiguration @TransactionConfiguration} and method-level
* {@link Rollback @Rollback} annotations.
* behavior can be configured declaratively via the {@link Rollback @Rollback}
* annotation at the class level and at the method level.
*
* <h3>Programmatic Transaction Management</h3>
* <p>As of Spring Framework 4.1, it is possible to interact with test-managed
@ -107,13 +105,11 @@ import static org.springframework.core.annotation.AnnotationUtils.*;
* {@link PlatformTransactionManager} bean to be defined in the Spring
* {@code ApplicationContext} for the test. In case there are multiple
* instances of {@code PlatformTransactionManager} within the test's
* {@code ApplicationContext}, {@code @TransactionConfiguration} supports
* configuring the bean name of the {@code PlatformTransactionManager} that
* should be used to drive transactions. Alternatively, a <em>qualifier</em>
* may be declared via
* {@link org.springframework.transaction.annotation.Transactional#value @Transactional("myQualifier")}, or
* {@link org.springframework.transaction.annotation.TransactionManagementConfigurer TransactionManagementConfigurer}
* can be implemented by an
* {@code ApplicationContext}, a <em>qualifier</em> may be declared via
* {@link org.springframework.transaction.annotation.Transactional @Transactional}
* (e.g., {@code @Transactional("myTxMgr")} or {@code @Transactional(transactionManger = "myTxMgr")},
* or {@link org.springframework.transaction.annotation.TransactionManagementConfigurer
* TransactionManagementConfigurer} can be implemented by an
* {@link org.springframework.context.annotation.Configuration @Configuration}
* class. See {@link TestContextTransactionUtils#retrieveTransactionManager}
* for details on the algorithm used to look up a transaction manager in
@ -122,7 +118,6 @@ import static org.springframework.core.annotation.AnnotationUtils.*;
* @author Sam Brannen
* @author Juergen Hoeller
* @since 2.5
* @see TransactionConfiguration
* @see org.springframework.transaction.annotation.TransactionManagementConfigurer
* @see org.springframework.transaction.annotation.Transactional
* @see org.springframework.test.annotation.Rollback
@ -134,8 +129,7 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
private static final Log logger = LogFactory.getLog(TransactionalTestExecutionListener.class);
private static final TransactionConfiguration defaultTransactionConfiguration =
AnnotationUtils.synthesizeAnnotation(TransactionConfiguration.class);
private static final TransactionConfigurationAttributes defaultTxConfigAttributes = new TransactionConfigurationAttributes();
protected final TransactionAttributeSource attributeSource = new AnnotationTransactionAttributeSource();
@ -229,8 +223,8 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
/**
* Run all {@link BeforeTransaction @BeforeTransaction} methods for the
* specified {@link TestContext test context}. If one of the methods fails,
* however, the caught exception will be rethrown in a wrapped
* specified {@linkplain TestContext test context}. If one of the methods
* fails, however, the caught exception will be rethrown in a wrapped
* {@link RuntimeException}, and the remaining methods will <strong>not</strong>
* be given a chance to execute.
* @param testContext the current test context
@ -255,8 +249,8 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
/**
* Run all {@link AfterTransaction @AfterTransaction} methods for the
* specified {@link TestContext test context}. If one of the methods fails,
* the caught exception will be logged as an error, and the remaining
* specified {@linkplain TestContext test context}. If one of the methods
* fails, the caught exception will be logged as an error, and the remaining
* methods will be given a chance to execute. After all methods have
* executed, the first caught exception, if any, will be rethrown.
* @param testContext the current test context
@ -295,7 +289,7 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
}
/**
* Get the {@link PlatformTransactionManager transaction manager} to use
* Get the {@linkplain PlatformTransactionManager transaction manager} to use
* for the supplied {@linkplain TestContext test context} and {@code qualifier}.
* <p>Delegates to {@link #getTransactionManager(TestContext)} if the
* supplied {@code qualifier} is {@code null} or empty.
@ -334,8 +328,8 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
}
/**
* Get the {@link PlatformTransactionManager transaction manager} to use
* for the supplied {@link TestContext test context}.
* Get the {@linkplain PlatformTransactionManager transaction manager}
* to use for the supplied {@linkplain TestContext test context}.
* <p>The default implementation simply delegates to
* {@link TestContextTransactionUtils#retrieveTransactionManager}.
* @param testContext the test context for which the transaction manager
@ -343,6 +337,8 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
* @return the transaction manager to use, or {@code null} if not found
* @throws BeansException if an error occurs while retrieving an explicitly
* named transaction manager
* @throws IllegalStateException if more than one TransactionManagementConfigurer
* exists in the ApplicationContext
* @see #getTransactionManager(TestContext, String)
*/
protected PlatformTransactionManager getTransactionManager(TestContext testContext) {
@ -352,21 +348,45 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
/**
* Determine whether or not to rollback transactions by default for the
* supplied {@link TestContext test context}.
* supplied {@linkplain TestContext test context}.
* <p>Supports {@link Rollback @Rollback} or
* {@link TransactionConfiguration @TransactionConfiguration} at the
* class-level.
* @param testContext the test context for which the default rollback flag
* should be retrieved
* @return the <em>default rollback</em> flag for the supplied test context
* @throws Exception if an error occurs while determining the default rollback flag
*/
protected final boolean isDefaultRollback(TestContext testContext) throws Exception {
return retrieveConfigurationAttributes(testContext).isDefaultRollback();
Class<?> testClass = testContext.getTestClass();
Rollback rollback = findAnnotation(testClass, Rollback.class);
boolean rollbackPresent = (rollback != null);
TransactionConfigurationAttributes txConfigAttributes = retrieveConfigurationAttributes(testContext);
if (rollbackPresent && txConfigAttributes != defaultTxConfigAttributes) {
throw new IllegalStateException(String.format("Test class [%s] is annotated with both @Rollback "
+ "and @TransactionConfiguration, but only one is permitted.", testClass.getName()));
}
if (rollbackPresent) {
boolean defaultRollback = rollback.value();
if (logger.isDebugEnabled()) {
logger.debug(String.format("Retrieved default @Rollback(%s) for test class [%s].", defaultRollback,
testClass.getName()));
}
return defaultRollback;
}
// else
return txConfigAttributes.isDefaultRollback();
}
/**
* Determine whether or not to rollback transactions for the supplied
* {@link TestContext test context} by taking into consideration the
* {@link #isDefaultRollback(TestContext) default rollback} flag and a
* possible method-level override via the {@link Rollback} annotation.
* {@linkplain TestContext test context} by taking into consideration the
* {@linkplain #isDefaultRollback(TestContext) default rollback} flag and a
* possible method-level override via the {@link Rollback @Rollback}
* annotation.
* @param testContext the test context for which the rollback flag
* should be retrieved
* @return the <em>rollback</em> flag for the supplied test context
@ -458,8 +478,8 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
}
/**
* Determine if the supplied {@link Method current method} is <em>shadowed</em>
* by a {@link Method previous method}.
* Determine if the supplied {@linkplain Method current method} is
* <em>shadowed</em> by a {@linkplain Method previous method}.
* <p>Note: This code has been borrowed from
* {@link org.junit.internal.runners.TestClass#isShadowed(Method, Method)}.
* @param current the current method
@ -482,17 +502,20 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
}
/**
* Retrieves the {@link TransactionConfigurationAttributes} for the
* specified {@link Class class} which may optionally declare or inherit
* {@link TransactionConfiguration @TransactionConfiguration}. If
* {@code @TransactionConfiguration} is not present for the supplied
* class, the <em>default values</em> for attributes defined in
* {@code @TransactionConfiguration} will be used instead.
* Retrieve the {@link TransactionConfigurationAttributes} for the
* supplied {@link TestContext} whose {@linkplain Class test class}
* may optionally declare or inherit
* {@link TransactionConfiguration @TransactionConfiguration}.
* <p>If {@code @TransactionConfiguration} is not present for the
* supplied {@code TestContext}, a default instance of
* {@code TransactionConfigurationAttributes} will be used instead.
* @param testContext the test context for which the configuration
* attributes should be retrieved
* @return the TransactionConfigurationAttributes instance for this listener,
* potentially cached
* @see TransactionConfigurationAttributes#TransactionConfigurationAttributes()
*/
@SuppressWarnings("deprecation")
TransactionConfigurationAttributes retrieveConfigurationAttributes(TestContext testContext) {
if (this.configurationAttributes == null) {
Class<?> clazz = testContext.getTestClass();
@ -501,18 +524,15 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
TransactionConfiguration.class);
if (logger.isDebugEnabled()) {
logger.debug(String.format("Retrieved @TransactionConfiguration [%s] for test class [%s].",
txConfig, clazz));
txConfig, clazz.getName()));
}
if (txConfig == null) {
txConfig = defaultTransactionConfiguration;
}
TransactionConfigurationAttributes configAttributes = (txConfig == null ? defaultTxConfigAttributes
: new TransactionConfigurationAttributes(txConfig.transactionManager(), txConfig.defaultRollback()));
TransactionConfigurationAttributes configAttributes = new TransactionConfigurationAttributes(
txConfig.transactionManager(), txConfig.defaultRollback());
if (logger.isDebugEnabled()) {
logger.debug(String.format("Using TransactionConfigurationAttributes %s for class [%s].",
configAttributes, clazz));
logger.debug(String.format("Using TransactionConfigurationAttributes %s for test class [%s].",
configAttributes, clazz.getName()));
}
this.configurationAttributes = configAttributes;
}

View File

@ -0,0 +1,110 @@
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.context.junit4;
import javax.sql.DataSource;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Transactional;
import static org.junit.Assert.*;
import static org.springframework.test.transaction.TransactionTestUtils.*;
/**
* Integration test which verifies proper transactional behavior when the
* default rollback flag is set to {@code false} via {@link Rollback @Rollback}.
*
* <p>Also tests configuration of the transaction manager qualifier configured
* via {@link Transactional @Transactional}.
*
* @author Sam Brannen
* @since 4.2
* @see Rollback
* @see Transactional#transactionManager
* @see DefaultRollbackFalseTransactionalTests
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(inheritLocations = false)
@Transactional("txMgr")
@Rollback(false)
public class DefaultRollbackFalseRollbackAnnotationTransactionalTests extends AbstractTransactionalSpringRunnerTests {
private static JdbcTemplate jdbcTemplate;
@Autowired
public void setDataSource(DataSource dataSource) {
jdbcTemplate = new JdbcTemplate(dataSource);
}
@Before
public void verifyInitialTestData() {
clearPersonTable(jdbcTemplate);
assertEquals("Adding bob", 1, addPerson(jdbcTemplate, BOB));
assertEquals("Verifying the initial number of rows in the person table.", 1,
countRowsInPersonTable(jdbcTemplate));
}
@Test
public void modifyTestDataWithinTransaction() {
assertInTransaction(true);
assertEquals("Deleting bob", 1, deletePerson(jdbcTemplate, BOB));
assertEquals("Adding jane", 1, addPerson(jdbcTemplate, JANE));
assertEquals("Adding sue", 1, addPerson(jdbcTemplate, SUE));
assertEquals("Verifying the number of rows in the person table within a transaction.", 2,
countRowsInPersonTable(jdbcTemplate));
}
@AfterClass
public static void verifyFinalTestData() {
assertEquals("Verifying the final number of rows in the person table after all tests.", 2,
countRowsInPersonTable(jdbcTemplate));
}
@Configuration
static class Config {
@Bean
public PlatformTransactionManager txMgr() {
return new DataSourceTransactionManager(dataSource());
}
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()//
.generateUniqueName(true)//
.addScript("classpath:/org/springframework/test/context/junit4/person-schema.sql") //
.build();
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -23,7 +23,6 @@ import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.transaction.TransactionConfiguration;
@ -33,33 +32,27 @@ import static org.junit.Assert.*;
import static org.springframework.test.transaction.TransactionTestUtils.*;
/**
* <p>
* JUnit 4 based integration test which verifies proper transactional behavior when the
* {@link TransactionConfiguration#defaultRollback() defaultRollback} attribute
* of the {@link TransactionConfiguration} annotation is set to <strong>{@code false}</strong>.
* Also tests configuration of the
* <p>Also tests configuration of the
* {@link TransactionConfiguration#transactionManager() transaction manager name}.
* </p>
*
* @author Sam Brannen
* @since 2.5
* @see TransactionConfiguration
* @see DefaultRollbackFalseRollbackAnnotationTransactionalTests
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@TransactionConfiguration(transactionManager = "txMgr", defaultRollback = false)
@Transactional
public class DefaultRollbackFalseTransactionalSpringRunnerTests extends AbstractTransactionalSpringRunnerTests {
@SuppressWarnings("deprecation")
public class DefaultRollbackFalseTransactionalTests extends AbstractTransactionalSpringRunnerTests {
protected static JdbcTemplate jdbcTemplate;
private static JdbcTemplate jdbcTemplate;
@AfterClass
public static void verifyFinalTestData() {
assertEquals("Verifying the final number of rows in the person table after all tests.", 2,
countRowsInPersonTable(jdbcTemplate));
}
@Before
public void verifyInitialTestData() {
clearPersonTable(jdbcTemplate);
@ -78,6 +71,12 @@ public class DefaultRollbackFalseTransactionalSpringRunnerTests extends Abstract
countRowsInPersonTable(jdbcTemplate));
}
@AfterClass
public static void verifyFinalTestData() {
assertEquals("Verifying the final number of rows in the person table after all tests.", 2,
countRowsInPersonTable(jdbcTemplate));
}
public static class DatabaseSetup {

View File

@ -0,0 +1,111 @@
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.context.junit4;
import javax.sql.DataSource;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Transactional;
import static org.junit.Assert.*;
import static org.springframework.test.transaction.TransactionTestUtils.*;
/**
* Integration test which verifies proper transactional behavior when the default
* rollback flag is explicitly set to {@code true} via {@link Rollback @Rollback}.
*
* <p>Also tests configuration of the transaction manager qualifier configured
* via {@link Transactional @Transactional}.
*
* @author Sam Brannen
* @since 4.2
* @see Rollback
* @see Transactional#transactionManager
* @see DefaultRollbackTrueTransactionalTests
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(inheritLocations = false)
@Transactional("txMgr")
@Rollback(true)
public class DefaultRollbackTrueRollbackAnnotationTransactionalTests extends AbstractTransactionalSpringRunnerTests {
private static int originalNumRows;
private static JdbcTemplate jdbcTemplate;
@Autowired
public void setDataSource(DataSource dataSource) {
jdbcTemplate = new JdbcTemplate(dataSource);
}
@Before
public void verifyInitialTestData() {
originalNumRows = clearPersonTable(jdbcTemplate);
assertEquals("Adding bob", 1, addPerson(jdbcTemplate, BOB));
assertEquals("Verifying the initial number of rows in the person table.", 1,
countRowsInPersonTable(jdbcTemplate));
}
@Test(timeout = 1000)
public void modifyTestDataWithinTransaction() {
assertInTransaction(true);
assertEquals("Adding jane", 1, addPerson(jdbcTemplate, JANE));
assertEquals("Adding sue", 1, addPerson(jdbcTemplate, SUE));
assertEquals("Verifying the number of rows in the person table within a transaction.", 3,
countRowsInPersonTable(jdbcTemplate));
}
@AfterClass
public static void verifyFinalTestData() {
assertEquals("Verifying the final number of rows in the person table after all tests.", originalNumRows,
countRowsInPersonTable(jdbcTemplate));
}
@Configuration
static class Config {
@Bean
public PlatformTransactionManager txMgr() {
return new DataSourceTransactionManager(dataSource());
}
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()//
.generateUniqueName(true)//
.addScript("classpath:/org/springframework/test/context/junit4/person-schema.sql") //
.build();
}
}
}

View File

@ -23,7 +23,6 @@ import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.transaction.TransactionConfiguration;
@ -43,20 +42,16 @@ import static org.springframework.test.transaction.TransactionTestUtils.*;
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@Transactional
@TransactionConfiguration(defaultRollback = true)
public class DefaultRollbackTrueTransactionalSpringRunnerTests extends AbstractTransactionalSpringRunnerTests {
@SuppressWarnings("deprecation")
public class DefaultRollbackTrueTransactionalTests extends AbstractTransactionalSpringRunnerTests {
protected static int originalNumRows;
private static int originalNumRows;
protected static JdbcTemplate jdbcTemplate;
private static JdbcTemplate jdbcTemplate;
@AfterClass
public static void verifyFinalTestData() {
assertEquals("Verifying the final number of rows in the person table after all tests.", originalNumRows,
countRowsInPersonTable(jdbcTemplate));
}
@Before
public void verifyInitialTestData() {
originalNumRows = clearPersonTable(jdbcTemplate);
@ -66,7 +61,6 @@ public class DefaultRollbackTrueTransactionalSpringRunnerTests extends AbstractT
}
@Test(timeout = 1000)
@Transactional
public void modifyTestDataWithinTransaction() {
assertInTransaction(true);
assertEquals("Adding jane", 1, addPerson(jdbcTemplate, JANE));
@ -75,6 +69,12 @@ public class DefaultRollbackTrueTransactionalSpringRunnerTests extends AbstractT
countRowsInPersonTable(jdbcTemplate));
}
@AfterClass
public static void verifyFinalTestData() {
assertEquals("Verifying the final number of rows in the person table after all tests.", originalNumRows,
countRowsInPersonTable(jdbcTemplate));
}
public static class DatabaseSetup {

View File

@ -0,0 +1,82 @@
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.context.junit4;
import javax.sql.DataSource;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.annotation.Rollback;
import static org.junit.Assert.*;
import static org.springframework.test.transaction.TransactionTestUtils.*;
/**
* Extension of {@link DefaultRollbackFalseRollbackAnnotationTransactionalTests}
* which tests method-level <em>rollback override</em> behavior via the
* {@link Rollback @Rollback} annotation.
*
* @author Sam Brannen
* @since 4.2
* @see Rollback
*/
public class RollbackOverrideDefaultRollbackFalseRollbackAnnotationTransactionalTests extends
DefaultRollbackFalseRollbackAnnotationTransactionalTests {
private static int originalNumRows;
private static JdbcTemplate jdbcTemplate;
@Autowired
public void setDataSource(DataSource dataSource) {
jdbcTemplate = new JdbcTemplate(dataSource);
}
@Before
@Override
public void verifyInitialTestData() {
originalNumRows = clearPersonTable(jdbcTemplate);
assertEquals("Adding bob", 1, addPerson(jdbcTemplate, BOB));
assertEquals("Verifying the initial number of rows in the person table.", 1,
countRowsInPersonTable(jdbcTemplate));
}
@Test
@Rollback
@Override
public void modifyTestDataWithinTransaction() {
assertInTransaction(true);
assertEquals("Deleting bob", 1, deletePerson(jdbcTemplate, BOB));
assertEquals("Adding jane", 1, addPerson(jdbcTemplate, JANE));
assertEquals("Adding sue", 1, addPerson(jdbcTemplate, SUE));
assertEquals("Verifying the number of rows in the person table within a transaction.", 2,
countRowsInPersonTable(jdbcTemplate));
}
@AfterClass
public static void verifyFinalTestData() {
assertEquals("Verifying the final number of rows in the person table after all tests.", originalNumRows,
countRowsInPersonTable(jdbcTemplate));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -31,7 +31,7 @@ import static org.junit.Assert.*;
import static org.springframework.test.transaction.TransactionTestUtils.*;
/**
* Extension of {@link DefaultRollbackFalseTransactionalSpringRunnerTests} which
* Extension of {@link DefaultRollbackFalseTransactionalTests} which
* tests method-level <em>rollback override</em> behavior via the
* {@link Rollback @Rollback} annotation.
*
@ -40,20 +40,14 @@ import static org.springframework.test.transaction.TransactionTestUtils.*;
* @see Rollback
*/
@ContextConfiguration
public class RollbackOverrideDefaultRollbackFalseTransactionalSpringRunnerTests extends
DefaultRollbackFalseTransactionalSpringRunnerTests {
public class RollbackOverrideDefaultRollbackFalseTransactionalTests extends
DefaultRollbackFalseTransactionalTests {
protected static int originalNumRows;
private static int originalNumRows;
protected static JdbcTemplate jdbcTemplate;
private static JdbcTemplate jdbcTemplate;
@AfterClass
public static void verifyFinalTestData() {
assertEquals("Verifying the final number of rows in the person table after all tests.", originalNumRows,
countRowsInPersonTable(jdbcTemplate));
}
@Before
@Override
public void verifyInitialTestData() {
@ -75,6 +69,12 @@ public class RollbackOverrideDefaultRollbackFalseTransactionalSpringRunnerTests
countRowsInPersonTable(jdbcTemplate));
}
@AfterClass
public static void verifyFinalTestData() {
assertEquals("Verifying the final number of rows in the person table after all tests.", originalNumRows,
countRowsInPersonTable(jdbcTemplate));
}
public static class DatabaseSetup {

View File

@ -0,0 +1,80 @@
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.context.junit4;
import javax.sql.DataSource;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.annotation.Rollback;
import static org.junit.Assert.*;
import static org.springframework.test.transaction.TransactionTestUtils.*;
/**
* Extension of {@link DefaultRollbackTrueRollbackAnnotationTransactionalTests}
* which tests method-level <em>rollback override</em> behavior via the
* {@link Rollback @Rollback} annotation.
*
* @author Sam Brannen
* @since 4.2
* @see Rollback
*/
public class RollbackOverrideDefaultRollbackTrueRollbackAnnotationTransactionalTests extends
DefaultRollbackTrueRollbackAnnotationTransactionalTests {
private static JdbcTemplate jdbcTemplate;
@Autowired
@Override
public void setDataSource(DataSource dataSource) {
jdbcTemplate = new JdbcTemplate(dataSource);
}
@Before
@Override
public void verifyInitialTestData() {
clearPersonTable(jdbcTemplate);
assertEquals("Adding bob", 1, addPerson(jdbcTemplate, BOB));
assertEquals("Verifying the initial number of rows in the person table.", 1,
countRowsInPersonTable(jdbcTemplate));
}
@Test
@Rollback(false)
@Override
public void modifyTestDataWithinTransaction() {
assertInTransaction(true);
assertEquals("Adding jane", 1, addPerson(jdbcTemplate, JANE));
assertEquals("Adding sue", 1, addPerson(jdbcTemplate, SUE));
assertEquals("Verifying the number of rows in the person table within a transaction.", 3,
countRowsInPersonTable(jdbcTemplate));
}
@AfterClass
public static void verifyFinalTestData() {
assertEquals("Verifying the final number of rows in the person table after all tests.", 3,
countRowsInPersonTable(jdbcTemplate));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -26,13 +26,12 @@ import org.junit.Test;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.transaction.annotation.Transactional;
import static org.junit.Assert.*;
import static org.springframework.test.transaction.TransactionTestUtils.*;
/**
* Extension of {@link DefaultRollbackTrueTransactionalSpringRunnerTests} which
* Extension of {@link DefaultRollbackTrueTransactionalTests} which
* tests method-level <em>rollback override</em> behavior via the
* {@link Rollback @Rollback} annotation.
*
@ -41,20 +40,14 @@ import static org.springframework.test.transaction.TransactionTestUtils.*;
* @see Rollback
*/
@ContextConfiguration
public class RollbackOverrideDefaultRollbackTrueTransactionalSpringRunnerTests extends
DefaultRollbackTrueTransactionalSpringRunnerTests {
public class RollbackOverrideDefaultRollbackTrueTransactionalTests extends
DefaultRollbackTrueTransactionalTests {
protected static JdbcTemplate jdbcTemplate;
private static JdbcTemplate jdbcTemplate;
@AfterClass
public static void verifyFinalTestData() {
assertEquals("Verifying the final number of rows in the person table after all tests.", 3,
countRowsInPersonTable(jdbcTemplate));
}
@Override
@Before
@Override
public void verifyInitialTestData() {
clearPersonTable(jdbcTemplate);
assertEquals("Adding bob", 1, addPerson(jdbcTemplate, BOB));
@ -62,10 +55,9 @@ public class RollbackOverrideDefaultRollbackTrueTransactionalSpringRunnerTests e
countRowsInPersonTable(jdbcTemplate));
}
@Override
@Test
@Transactional
@Rollback(false)
@Override
public void modifyTestDataWithinTransaction() {
assertInTransaction(true);
assertEquals("Adding jane", 1, addPerson(jdbcTemplate, JANE));
@ -74,6 +66,12 @@ public class RollbackOverrideDefaultRollbackTrueTransactionalSpringRunnerTests e
countRowsInPersonTable(jdbcTemplate));
}
@AfterClass
public static void verifyFinalTestData() {
assertEquals("Verifying the final number of rows in the person table after all tests.", 3,
countRowsInPersonTable(jdbcTemplate));
}
public static class DatabaseSetup {

View File

@ -55,7 +55,7 @@ import org.springframework.test.context.transaction.programmatic.ProgrammaticTxM
*
* <p>Note that tests included in this suite will be executed at least twice if
* run from an automated build process, test runner, etc. that is not configured
* to exclude tests based on a &quot;*TestSuite.class&quot; pattern match.
* to exclude tests based on a {@code "*TestSuite.class"} pattern match.
*
* @author Sam Brannen
* @since 2.5
@ -104,10 +104,10 @@ StandardJUnit4FeaturesTests.class,//
ConcreteTransactionalJUnit4SpringContextTests.class,//
ClassLevelTransactionalSpringRunnerTests.class,//
MethodLevelTransactionalSpringRunnerTests.class,//
DefaultRollbackTrueTransactionalSpringRunnerTests.class,//
DefaultRollbackFalseTransactionalSpringRunnerTests.class,//
RollbackOverrideDefaultRollbackTrueTransactionalSpringRunnerTests.class,//
RollbackOverrideDefaultRollbackFalseTransactionalSpringRunnerTests.class,//
DefaultRollbackTrueTransactionalTests.class,//
DefaultRollbackFalseTransactionalTests.class,//
RollbackOverrideDefaultRollbackTrueTransactionalTests.class,//
RollbackOverrideDefaultRollbackFalseTransactionalTests.class,//
BeforeAndAfterTransactionAnnotationTests.class,//
TimedTransactionalSpringRunnerTests.class,//
ProgrammaticTxMgmtTests.class,//

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -20,9 +20,13 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.BDDMockito;
import org.springframework.core.annotation.AliasFor;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.TestContext;
import org.springframework.transaction.PlatformTransactionManager;
@ -31,6 +35,8 @@ import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.SimpleTransactionStatus;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.mockito.BDDMockito.*;
import static org.springframework.transaction.annotation.Propagation.*;
@ -41,6 +47,7 @@ import static org.springframework.transaction.annotation.Propagation.*;
* @author Sam Brannen
* @since 4.0
*/
@SuppressWarnings("deprecation")
public class TransactionalTestExecutionListenerTests {
private final PlatformTransactionManager tm = mock(PlatformTransactionManager.class);
@ -54,6 +61,9 @@ public class TransactionalTestExecutionListenerTests {
private final TestContext testContext = mock(TestContext.class);
@Rule
public ExpectedException exception = ExpectedException.none();
private void assertBeforeTestMethod(Class<? extends Invocable> clazz) throws Exception {
assertBeforeTestMethodWithTransactionalTestMethod(clazz);
@ -228,24 +238,86 @@ public class TransactionalTestExecutionListenerTests {
"overriddenTxMgr", true);
}
@Test
public void retrieveConfigurationAttributesWithEmptyTransactionalAnnotation() throws Exception {
assertTransactionConfigurationAttributes(EmptyTransactionalTestCase.class, "", true);
}
@Test
public void retrieveConfigurationAttributesFromTransactionalAnnotationWithExplicitQualifier() throws Exception {
// The test class configures "tm" as the qualifier via @Transactional;
// however, retrieveConfigurationAttributes() only supports
// @TransactionConfiguration. So we actually expect "" as the qualifier here,
// relying on beforeTestMethod() to properly obtain the actual qualifier via the
// TransactionAttribute.
assertTransactionConfigurationAttributes(TransactionalWithExplicitQualifierTestCase.class, "", true);
}
@Test
public void retrieveConfigurationAttributesFromTransactionalAnnotationViaMetaAnnotation() throws Exception {
// The test class configures "metaTxMgr" as the qualifier via @Transactional;
// however, retrieveConfigurationAttributes() only supports
// @TransactionConfiguration. So we actually expect "" as the qualifier here,
// relying on beforeTestMethod() to properly obtain the actual qualifier via the
// TransactionAttribute.
assertTransactionConfigurationAttributes(TransactionalViaMetaAnnotationTestCase.class, "", true);
}
@Test
public void retrieveConfigurationAttributesFromTransactionalAnnotationViaMetaAnnotationWithExplicitQualifier()
throws Exception {
// The test class configures "overriddenTxMgr" as the qualifier via
// @Transactional; however, retrieveConfigurationAttributes() only supports
// @TransactionConfiguration. So we actually expect "" as the qualifier here,
// relying on beforeTestMethod() to properly obtain the actual qualifier via the
// TransactionAttribute.
assertTransactionConfigurationAttributes(TransactionalViaMetaAnnotationWithExplicitQualifierTestCase.class, "",
true);
}
@Test
public void isRollbackWithMissingRollback() throws Exception {
assertIsRollback(MissingRollbackTestCase.class, true);
}
@Test
public void isRollbackWithEmptyRollback() throws Exception {
assertIsRollback(EmptyRollbackTestCase.class, true);
public void isRollbackWithEmptyMethodLevelRollback() throws Exception {
assertIsRollback(EmptyMethodLevelRollbackTestCase.class, true);
}
@Test
public void isRollbackWithExplicitValue() throws Exception {
assertIsRollback(RollbackWithExplicitValueTestCase.class, false);
public void isRollbackWithMethodLevelRollbackWithExplicitValue() throws Exception {
assertIsRollback(MethodLevelRollbackWithExplicitValueTestCase.class, false);
}
@Test
public void isRollbackViaMetaAnnotation() throws Exception {
assertIsRollback(RollbackViaMetaAnnotationTestCase.class, false);
public void isRollbackWithMethodLevelRollbackViaMetaAnnotation() throws Exception {
assertIsRollback(MethodLevelRollbackViaMetaAnnotationTestCase.class, false);
}
@Test
public void isRollbackWithEmptyClassLevelRollback() throws Exception {
assertIsRollback(EmptyClassLevelRollbackTestCase.class, true);
}
@Test
public void isRollbackWithClassLevelRollbackWithExplicitValue() throws Exception {
assertIsRollback(ClassLevelRollbackWithExplicitValueTestCase.class, false);
}
@Test
public void isRollbackWithClassLevelRollbackViaMetaAnnotation() throws Exception {
assertIsRollback(ClassLevelRollbackViaMetaAnnotationTestCase.class, false);
}
@Test
public void isRollbackWithRollbackAndTransactionConfigurationDeclaredAtClassLevel() throws Exception {
Class<?> clazz = ClassLevelRollbackAndTransactionConfigurationTestCase.class;
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
exception.expect(IllegalStateException.class);
exception.expectMessage(containsString("annotated with both @Rollback and @TransactionConfiguration, but only one is permitted"));
listener.isRollback(testContext);
}
@ -260,6 +332,9 @@ public class TransactionalTestExecutionListenerTests {
@Retention(RetentionPolicy.RUNTIME)
private static @interface MetaTxWithOverride {
@AliasFor(annotation = Transactional.class, attribute = "value")
String transactionManager() default "";
Propagation propagation() default REQUIRED;
}
@ -467,31 +542,76 @@ public class TransactionalTestExecutionListenerTests {
static class TransactionConfigurationViaMetaAnnotationWithOverrideTestCase {
}
@Transactional
static class EmptyTransactionalTestCase {
}
@Transactional(transactionManager = "tm")
static class TransactionalWithExplicitQualifierTestCase {
}
@MetaTransactional
static class TransactionalViaMetaAnnotationTestCase {
}
@MetaTxWithOverride(transactionManager = "tm")
static class TransactionalViaMetaAnnotationWithExplicitQualifierTestCase {
}
static class MissingRollbackTestCase {
public void test() {
}
}
static class EmptyRollbackTestCase {
static class EmptyMethodLevelRollbackTestCase {
@Rollback
public void test() {
}
}
static class RollbackWithExplicitValueTestCase {
static class MethodLevelRollbackWithExplicitValueTestCase {
@Rollback(false)
public void test() {
}
}
static class RollbackViaMetaAnnotationTestCase {
static class MethodLevelRollbackViaMetaAnnotationTestCase {
@Commit
public void test() {
}
}
@Rollback
@TransactionConfiguration
static class ClassLevelRollbackAndTransactionConfigurationTestCase {
public void test() {
}
}
@Rollback
static class EmptyClassLevelRollbackTestCase {
public void test() {
}
}
@Rollback(false)
static class ClassLevelRollbackWithExplicitValueTestCase {
public void test() {
}
}
@Commit
static class ClassLevelRollbackViaMetaAnnotationTestCase {
public void test() {
}
}
}

View File

@ -10,6 +10,6 @@
p:data-source-ref="dataSource" />
<bean id="databaseSetup"
class="org.springframework.test.context.junit4.DefaultRollbackFalseTransactionalSpringRunnerTests$DatabaseSetup" />
class="org.springframework.test.context.junit4.DefaultRollbackFalseTransactionalTests$DatabaseSetup" />
</beans>

View File

@ -3,6 +3,6 @@
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="databaseSetup"
class="org.springframework.test.context.junit4.DefaultRollbackTrueTransactionalSpringRunnerTests$DatabaseSetup" />
class="org.springframework.test.context.junit4.DefaultRollbackTrueTransactionalTests$DatabaseSetup" />
</beans>

View File

@ -10,6 +10,6 @@
p:data-source-ref="dataSource" />
<bean id="databaseSetup"
class="org.springframework.test.context.junit4.RollbackOverrideDefaultRollbackFalseTransactionalSpringRunnerTests$DatabaseSetup" />
class="org.springframework.test.context.junit4.RollbackOverrideDefaultRollbackFalseTransactionalTests$DatabaseSetup" />
</beans>

View File

@ -3,6 +3,6 @@
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="databaseSetup"
class="org.springframework.test.context.junit4.RollbackOverrideDefaultRollbackTrueTransactionalSpringRunnerTests$DatabaseSetup" />
class="org.springframework.test.context.junit4.RollbackOverrideDefaultRollbackTrueTransactionalTests$DatabaseSetup" />
</beans>

View File

@ -0,0 +1 @@
CREATE TABLE person (name VARCHAR(20) NOT NULL, PRIMARY KEY(name))

View File

@ -264,8 +264,7 @@ application context.
If you want a transaction to commit -- unusual, but occasionally useful when you want a
particular test to populate or modify the database -- the TestContext framework can be
instructed to cause the transaction to commit instead of roll back via the
<<integration-testing-annotations, `@TransactionConfiguration`>> and
<<integration-testing-annotations, `@Rollback`>> annotations.
<<integration-testing-annotations, `@Rollback`>> annotation.
See transaction management with the <<testcontext-tx,TestContext framework>>.
@ -798,53 +797,22 @@ in conjunction with `@ContextConfiguration`.
`@TestExecutionListeners` supports __inherited__ listeners by default. See the javadocs
for an example and further details.
* `@TransactionConfiguration`
+
Defines class-level metadata for configuring transactional tests. Specifically, the bean
name of the `PlatformTransactionManager` that should be used to drive transactions can
be explicitly specified if there are multiple beans of type `PlatformTransactionManager`
in the test's `ApplicationContext` and if the bean name of the desired
`PlatformTransactionManager` is not "transactionManager". In addition, you can change
the `defaultRollback` flag to `false`. Typically, `@TransactionConfiguration` is used in
conjunction with `@ContextConfiguration`.
+
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ContextConfiguration
**@TransactionConfiguration**(**transactionManager** = "txMgr", **defaultRollback** = false)
public class CustomConfiguredTransactionalTests {
// class body...
}
----
+
[NOTE]
====
If the default conventions are sufficient for your test configuration, you can avoid
using `@TransactionConfiguration` altogether. In other words, if you have only one
transaction manager -- or if you have multiple transaction managers but the transaction
manager for tests is named "transactionManager" or specified via a
`TransactionManagementConfigurer` -- and if you want transactions to roll back
automatically, then there is no need to annotate your test class with
`@TransactionConfiguration`.
====
+
* `@Rollback`
+
Indicates whether the transaction for the annotated test method should be __rolled
Indicates whether the transaction for a transactional test method should be __rolled
back__ after the test method has completed. If `true`, the transaction is rolled back;
otherwise, the transaction is committed. Use `@Rollback` to override the default
rollback flag configured at the class level.
otherwise, the transaction is committed.
+
When declared as a class-level annotation, `@Rollback` defines the default rollback
semantics for all test methods within the test class hierarchy. When declared as a
method-level annotation, `@Rollback` defines rollback semantics for the specific test
method, potentially overriding class-level default rollback semantics.
+
@ -1150,7 +1118,6 @@ Each of the following may be used as meta-annotations in conjunction with the
* `@Transactional`
* `@BeforeTransaction`
* `@AfterTransaction`
* `@TransactionConfiguration`
* `@Rollback`
* `@Sql`
* `@SqlConfig`
@ -2398,12 +2365,12 @@ need to override this default, simply provide an alternate path to the
you wish to reference a base resource path from the classpath instead of the file
system, just use Spring's __classpath:__ prefix.
Please note that Spring's testing support for `WebApplicationContexts` is on par with
its support for standard `ApplicationContexts`. When testing with a
`WebApplicationContext` you are free to declare either XML configuration files or
`@Configuration` classes via `@ContextConfiguration`. You are of course also free to use
any other test annotations such as `@TestExecutionListeners`,
`@TransactionConfiguration`, `@ActiveProfiles`, etc.
Please note that Spring's testing support for `WebApplicationContexts` is on par with its
support for standard `ApplicationContexts`. When testing with a `WebApplicationContext`
you are free to declare XML configuration files, Groovy scripts, or `@Configuration`
classes via `@ContextConfiguration`. You are of course also free to use any other test
annotations such as `@ActiveProfiles`, `@TestExecutionListeners`, `@Sql`, `@Rollback`,
etc.
The following examples demonstrate some of the various configuration options for loading
a `WebApplicationContext`.
@ -3150,9 +3117,8 @@ See <<testing-examples-petclinic>> for an additional example.
By default, test transactions will be automatically rolled back after completion of the
test; however, transactional commit and rollback behavior can be configured declaratively
via the class-level `@TransactionConfiguration` and method-level `@Rollback` annotations.
See the corresponding entries in the <<integration-testing-annotations,annotation
support>> section for further details.
via the `@Rollback` annotation. See the corresponding entry in the
<<integration-testing-annotations,annotation support>> section for further details.
[[testcontext-tx-programmatic-tx-mgt]]
===== Programmatic transaction management
@ -3224,14 +3190,12 @@ to run within a transaction.
`TransactionalTestExecutionListener` expects a `PlatformTransactionManager` bean to be
defined in the Spring `ApplicationContext` for the test. In case there are multiple
instances of `PlatformTransactionManager` within the test's `ApplicationContext`,
`@TransactionConfiguration` supports configuring the bean name of the
`PlatformTransactionManager` that should be used to drive transactions. Alternatively, a
_qualifier_ may be declared via `@Transactional("myQualifier")`, or
`TransactionManagementConfigurer` can be implemented by an `@Configuration` class.
Consult the javadocs for `TestContextTransactionUtils.retrieveTransactionManager()` for
details on the algorithm used to look up a transaction manager in the test's
`ApplicationContext`.
instances of `PlatformTransactionManager` within the test's `ApplicationContext`, a
_qualifier_ may be declared via `@Transactional("myTxMgr")` or
`@Transactional(transactionManager = "myTxMgr")`, or `TransactionManagementConfigurer`
can be implemented by an `@Configuration` class. Consult the javadocs for
`TestContextTransactionUtils.retrieveTransactionManager()` for details on the algorithm
used to look up a transaction manager in the test's `ApplicationContext`.
[[testcontext-tx-annotation-demo]]
===== Demonstration of all transaction-related annotations
@ -3249,8 +3213,8 @@ declarative SQL script execution with default transaction rollback semantics.
----
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
**@TransactionConfiguration(transactionManager="txMgr", defaultRollback=false)
@Transactional**
@Transactional(transactionManager = "txMgr")
**@Rollback(false)**
public class FictitiousTransactionalTest {
**@BeforeTransaction**
@ -3264,7 +3228,7 @@ declarative SQL script execution with default transaction rollback semantics.
}
@Test
// overrides the class-level defaultRollback setting
// overrides the class-level default rollback setting
**@Rollback(true)**
public void modifyDatabaseWithinTransaction() {
// logic which uses the test data and modifies database state

View File

@ -577,6 +577,9 @@ public @interface MyTestConfig {
_before_ a test -- for example, if some rogue (i.e., yet to be
determined) test within a large test suite has corrupted the original
configuration for the `ApplicationContext`.
* `@Rollback` may now be used to configure class-level _default rollback_ semantics.
** Consequently, `@TransactionConfiguration` is now deprecated and will be removed in a
subsequent release.
* `@Sql` now supports execution of _inlined SQL statements_ via a new
`statements` attribute.
* The `ContextCache` that is used for caching ++ApplicationContext++s