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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.*; import static java.lang.annotation.RetentionPolicy.*;
/** /**
* Test annotation used to indicate whether or not the transaction for the * Test annotation used to indicate whether a <em>test-managed transaction</em>
* annotated test method should be <em>rolled back</em> after the test method * should be <em>rolled back</em> after the test method has completed.
* has completed. If {@code true}, the transaction will be rolled back; *
* otherwise, the transaction will be committed. * <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 * <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>. * <em>meta-annotation</em> to create custom <em>composed annotations</em>.
* *
* @author Sam Brannen * @author Sam Brannen
* @since 2.5 * @since 2.5
* @see org.springframework.test.context.transaction.TransactionalTestExecutionListener
*/ */
@Documented @Documented
@Retention(RUNTIME) @Retention(RUNTIME)
@Target({ METHOD, ANNOTATION_TYPE }) @Target({ TYPE, METHOD, ANNOTATION_TYPE })
public @interface Rollback { public @interface Rollback {
/** /**
* Whether or not the transaction for the annotated method should be rolled * Whether the <em>test-managed transaction</em> should be rolled back
* back after the method has completed. * 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; 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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 * Utility methods for working with transactions and data access related beans
* within the <em>Spring TestContext Framework</em>. Mainly for internal use * within the <em>Spring TestContext Framework</em>.
* within the framework. * <p>Mainly for internal use within the framework.
* *
* @author Sam Brannen * @author Sam Brannen
* @author Juergen Hoeller * @author Juergen Hoeller
@ -146,6 +146,8 @@ public abstract class TestContextTransactionUtils {
* @return the transaction manager to use, or {@code null} if not found * @return the transaction manager to use, or {@code null} if not found
* @throws BeansException if an error occurs while retrieving an explicitly * @throws BeansException if an error occurs while retrieving an explicitly
* named transaction manager * named transaction manager
* @throws IllegalStateException if more than one TransactionManagementConfigurer
* exists in the ApplicationContext
*/ */
public static PlatformTransactionManager retrieveTransactionManager(TestContext testContext, String name) { public static PlatformTransactionManager retrieveTransactionManager(TestContext testContext, String name) {
Assert.notNull(testContext, "TestContext must not be null"); 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
* @see org.springframework.test.context.jdbc.SqlConfig#transactionManager * @see org.springframework.test.context.jdbc.SqlConfig#transactionManager
* @see org.springframework.test.context.ContextConfiguration * @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 @Documented
@Inherited @Inherited
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@ -48,7 +51,7 @@ public @interface TransactionConfiguration {
/** /**
* The bean name of the {@link org.springframework.transaction.PlatformTransactionManager * 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 * <p>The name is only used if there is more than one bean of type
* {@code PlatformTransactionManager} in the test's {@code ApplicationContext}. * {@code PlatformTransactionManager} in the test's {@code ApplicationContext}.
@ -76,7 +79,7 @@ public @interface TransactionConfiguration {
String transactionManager() default ""; 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; 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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 * Construct a new {@code TransactionConfigurationAttributes} instance
* supplied arguments. * 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 * @param transactionManagerName the bean name of the
* {@link PlatformTransactionManager} that is to be used to drive transactions * {@link PlatformTransactionManager} that is to be used to drive
* @param defaultRollback whether or not transactions should be rolled back by default * <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) { 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.transactionManagerName = transactionManagerName;
this.defaultRollback = defaultRollback; this.defaultRollback = defaultRollback;
} }
@ -51,14 +64,14 @@ public class TransactionConfigurationAttributes {
/** /**
* Get the bean name of the {@link PlatformTransactionManager} that is to * 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() { public final String getTransactionManagerName() {
return this.transactionManagerName; 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 * @return the <em>default rollback</em> flag
*/ */
public final boolean isDefaultRollback() { 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.BeanFactory;
import org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils; import org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils;
import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.test.annotation.Rollback; import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.TestContext; import org.springframework.test.context.TestContext;
import org.springframework.test.context.support.AbstractTestExecutionListener; 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> * <h3>Declarative Rollback and Commit Behavior</h3>
* <p>By default, test transactions will be automatically <em>rolled back</em> * <p>By default, test transactions will be automatically <em>rolled back</em>
* after completion of the test; however, transactional commit and rollback * after completion of the test; however, transactional commit and rollback
* behavior can be configured declaratively via the class-level * behavior can be configured declaratively via the {@link Rollback @Rollback}
* {@link TransactionConfiguration @TransactionConfiguration} and method-level * annotation at the class level and at the method level.
* {@link Rollback @Rollback} annotations.
* *
* <h3>Programmatic Transaction Management</h3> * <h3>Programmatic Transaction Management</h3>
* <p>As of Spring Framework 4.1, it is possible to interact with test-managed * <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 * {@link PlatformTransactionManager} bean to be defined in the Spring
* {@code ApplicationContext} for the test. In case there are multiple * {@code ApplicationContext} for the test. In case there are multiple
* instances of {@code PlatformTransactionManager} within the test's * instances of {@code PlatformTransactionManager} within the test's
* {@code ApplicationContext}, {@code @TransactionConfiguration} supports * {@code ApplicationContext}, a <em>qualifier</em> may be declared via
* configuring the bean name of the {@code PlatformTransactionManager} that * {@link org.springframework.transaction.annotation.Transactional @Transactional}
* should be used to drive transactions. Alternatively, a <em>qualifier</em> * (e.g., {@code @Transactional("myTxMgr")} or {@code @Transactional(transactionManger = "myTxMgr")},
* may be declared via * or {@link org.springframework.transaction.annotation.TransactionManagementConfigurer
* {@link org.springframework.transaction.annotation.Transactional#value @Transactional("myQualifier")}, or * TransactionManagementConfigurer} can be implemented by an
* {@link org.springframework.transaction.annotation.TransactionManagementConfigurer TransactionManagementConfigurer}
* can be implemented by an
* {@link org.springframework.context.annotation.Configuration @Configuration} * {@link org.springframework.context.annotation.Configuration @Configuration}
* class. See {@link TestContextTransactionUtils#retrieveTransactionManager} * class. See {@link TestContextTransactionUtils#retrieveTransactionManager}
* for details on the algorithm used to look up a transaction manager in * 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 Sam Brannen
* @author Juergen Hoeller * @author Juergen Hoeller
* @since 2.5 * @since 2.5
* @see TransactionConfiguration
* @see org.springframework.transaction.annotation.TransactionManagementConfigurer * @see org.springframework.transaction.annotation.TransactionManagementConfigurer
* @see org.springframework.transaction.annotation.Transactional * @see org.springframework.transaction.annotation.Transactional
* @see org.springframework.test.annotation.Rollback * @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 Log logger = LogFactory.getLog(TransactionalTestExecutionListener.class);
private static final TransactionConfiguration defaultTransactionConfiguration = private static final TransactionConfigurationAttributes defaultTxConfigAttributes = new TransactionConfigurationAttributes();
AnnotationUtils.synthesizeAnnotation(TransactionConfiguration.class);
protected final TransactionAttributeSource attributeSource = new AnnotationTransactionAttributeSource(); protected final TransactionAttributeSource attributeSource = new AnnotationTransactionAttributeSource();
@ -229,8 +223,8 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
/** /**
* Run all {@link BeforeTransaction @BeforeTransaction} methods for the * Run all {@link BeforeTransaction @BeforeTransaction} methods for the
* specified {@link TestContext test context}. If one of the methods fails, * specified {@linkplain TestContext test context}. If one of the methods
* however, the caught exception will be rethrown in a wrapped * fails, however, the caught exception will be rethrown in a wrapped
* {@link RuntimeException}, and the remaining methods will <strong>not</strong> * {@link RuntimeException}, and the remaining methods will <strong>not</strong>
* be given a chance to execute. * be given a chance to execute.
* @param testContext the current test context * @param testContext the current test context
@ -255,8 +249,8 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
/** /**
* Run all {@link AfterTransaction @AfterTransaction} methods for the * Run all {@link AfterTransaction @AfterTransaction} methods for the
* specified {@link TestContext test context}. If one of the methods fails, * specified {@linkplain TestContext test context}. If one of the methods
* the caught exception will be logged as an error, and the remaining * 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 * methods will be given a chance to execute. After all methods have
* executed, the first caught exception, if any, will be rethrown. * executed, the first caught exception, if any, will be rethrown.
* @param testContext the current test context * @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}. * for the supplied {@linkplain TestContext test context} and {@code qualifier}.
* <p>Delegates to {@link #getTransactionManager(TestContext)} if the * <p>Delegates to {@link #getTransactionManager(TestContext)} if the
* supplied {@code qualifier} is {@code null} or empty. * 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 * Get the {@linkplain PlatformTransactionManager transaction manager}
* for the supplied {@link TestContext test context}. * to use for the supplied {@linkplain TestContext test context}.
* <p>The default implementation simply delegates to * <p>The default implementation simply delegates to
* {@link TestContextTransactionUtils#retrieveTransactionManager}. * {@link TestContextTransactionUtils#retrieveTransactionManager}.
* @param testContext the test context for which the transaction manager * @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 * @return the transaction manager to use, or {@code null} if not found
* @throws BeansException if an error occurs while retrieving an explicitly * @throws BeansException if an error occurs while retrieving an explicitly
* named transaction manager * named transaction manager
* @throws IllegalStateException if more than one TransactionManagementConfigurer
* exists in the ApplicationContext
* @see #getTransactionManager(TestContext, String) * @see #getTransactionManager(TestContext, String)
*/ */
protected PlatformTransactionManager getTransactionManager(TestContext testContext) { 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 * 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 * @param testContext the test context for which the default rollback flag
* should be retrieved * should be retrieved
* @return the <em>default rollback</em> flag for the supplied test context * @return the <em>default rollback</em> flag for the supplied test context
* @throws Exception if an error occurs while determining the default rollback flag * @throws Exception if an error occurs while determining the default rollback flag
*/ */
protected final boolean isDefaultRollback(TestContext testContext) throws Exception { 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 * Determine whether or not to rollback transactions for the supplied
* {@link TestContext test context} by taking into consideration the * {@linkplain TestContext test context} by taking into consideration the
* {@link #isDefaultRollback(TestContext) default rollback} flag and a * {@linkplain #isDefaultRollback(TestContext) default rollback} flag and a
* possible method-level override via the {@link Rollback} annotation. * possible method-level override via the {@link Rollback @Rollback}
* annotation.
* @param testContext the test context for which the rollback flag * @param testContext the test context for which the rollback flag
* should be retrieved * should be retrieved
* @return the <em>rollback</em> flag for the supplied test context * @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> * Determine if the supplied {@linkplain Method current method} is
* by a {@link Method previous method}. * <em>shadowed</em> by a {@linkplain Method previous method}.
* <p>Note: This code has been borrowed from * <p>Note: This code has been borrowed from
* {@link org.junit.internal.runners.TestClass#isShadowed(Method, Method)}. * {@link org.junit.internal.runners.TestClass#isShadowed(Method, Method)}.
* @param current the current method * @param current the current method
@ -482,17 +502,20 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
} }
/** /**
* Retrieves the {@link TransactionConfigurationAttributes} for the * Retrieve the {@link TransactionConfigurationAttributes} for the
* specified {@link Class class} which may optionally declare or inherit * supplied {@link TestContext} whose {@linkplain Class test class}
* {@link TransactionConfiguration @TransactionConfiguration}. If * may optionally declare or inherit
* {@code @TransactionConfiguration} is not present for the supplied * {@link TransactionConfiguration @TransactionConfiguration}.
* class, the <em>default values</em> for attributes defined in * <p>If {@code @TransactionConfiguration} is not present for the
* {@code @TransactionConfiguration} will be used instead. * supplied {@code TestContext}, a default instance of
* {@code TransactionConfigurationAttributes} will be used instead.
* @param testContext the test context for which the configuration * @param testContext the test context for which the configuration
* attributes should be retrieved * attributes should be retrieved
* @return the TransactionConfigurationAttributes instance for this listener, * @return the TransactionConfigurationAttributes instance for this listener,
* potentially cached * potentially cached
* @see TransactionConfigurationAttributes#TransactionConfigurationAttributes()
*/ */
@SuppressWarnings("deprecation")
TransactionConfigurationAttributes retrieveConfigurationAttributes(TestContext testContext) { TransactionConfigurationAttributes retrieveConfigurationAttributes(TestContext testContext) {
if (this.configurationAttributes == null) { if (this.configurationAttributes == null) {
Class<?> clazz = testContext.getTestClass(); Class<?> clazz = testContext.getTestClass();
@ -501,18 +524,15 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
TransactionConfiguration.class); TransactionConfiguration.class);
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug(String.format("Retrieved @TransactionConfiguration [%s] for test class [%s].", logger.debug(String.format("Retrieved @TransactionConfiguration [%s] for test class [%s].",
txConfig, clazz)); txConfig, clazz.getName()));
} }
if (txConfig == null) { TransactionConfigurationAttributes configAttributes = (txConfig == null ? defaultTxConfigAttributes
txConfig = defaultTransactionConfiguration; : new TransactionConfigurationAttributes(txConfig.transactionManager(), txConfig.defaultRollback()));
}
TransactionConfigurationAttributes configAttributes = new TransactionConfigurationAttributes(
txConfig.transactionManager(), txConfig.defaultRollback());
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug(String.format("Using TransactionConfigurationAttributes %s for class [%s].", logger.debug(String.format("Using TransactionConfigurationAttributes %s for test class [%s].",
configAttributes, clazz)); configAttributes, clazz.getName()));
} }
this.configurationAttributes = configAttributes; 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.transaction.TransactionConfiguration; import org.springframework.test.context.transaction.TransactionConfiguration;
@ -33,33 +32,27 @@ import static org.junit.Assert.*;
import static org.springframework.test.transaction.TransactionTestUtils.*; import static org.springframework.test.transaction.TransactionTestUtils.*;
/** /**
* <p>
* JUnit 4 based integration test which verifies proper transactional behavior when the * JUnit 4 based integration test which verifies proper transactional behavior when the
* {@link TransactionConfiguration#defaultRollback() defaultRollback} attribute * {@link TransactionConfiguration#defaultRollback() defaultRollback} attribute
* of the {@link TransactionConfiguration} annotation is set to <strong>{@code false}</strong>. * 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}. * {@link TransactionConfiguration#transactionManager() transaction manager name}.
* </p>
* *
* @author Sam Brannen * @author Sam Brannen
* @since 2.5 * @since 2.5
* @see TransactionConfiguration * @see TransactionConfiguration
* @see DefaultRollbackFalseRollbackAnnotationTransactionalTests
*/ */
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration @ContextConfiguration
@TransactionConfiguration(transactionManager = "txMgr", defaultRollback = false) @TransactionConfiguration(transactionManager = "txMgr", defaultRollback = false)
@Transactional @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 @Before
public void verifyInitialTestData() { public void verifyInitialTestData() {
clearPersonTable(jdbcTemplate); clearPersonTable(jdbcTemplate);
@ -78,6 +71,12 @@ public class DefaultRollbackFalseTransactionalSpringRunnerTests extends Abstract
countRowsInPersonTable(jdbcTemplate)); 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 { 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.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.transaction.TransactionConfiguration; import org.springframework.test.context.transaction.TransactionConfiguration;
@ -43,20 +42,16 @@ import static org.springframework.test.transaction.TransactionTestUtils.*;
*/ */
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration @ContextConfiguration
@Transactional
@TransactionConfiguration(defaultRollback = true) @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 @Before
public void verifyInitialTestData() { public void verifyInitialTestData() {
originalNumRows = clearPersonTable(jdbcTemplate); originalNumRows = clearPersonTable(jdbcTemplate);
@ -66,7 +61,6 @@ public class DefaultRollbackTrueTransactionalSpringRunnerTests extends AbstractT
} }
@Test(timeout = 1000) @Test(timeout = 1000)
@Transactional
public void modifyTestDataWithinTransaction() { public void modifyTestDataWithinTransaction() {
assertInTransaction(true); assertInTransaction(true);
assertEquals("Adding jane", 1, addPerson(jdbcTemplate, JANE)); assertEquals("Adding jane", 1, addPerson(jdbcTemplate, JANE));
@ -75,6 +69,12 @@ public class DefaultRollbackTrueTransactionalSpringRunnerTests extends AbstractT
countRowsInPersonTable(jdbcTemplate)); 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 { 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.*; 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 * tests method-level <em>rollback override</em> behavior via the
* {@link Rollback @Rollback} annotation. * {@link Rollback @Rollback} annotation.
* *
@ -40,20 +40,14 @@ import static org.springframework.test.transaction.TransactionTestUtils.*;
* @see Rollback * @see Rollback
*/ */
@ContextConfiguration @ContextConfiguration
public class RollbackOverrideDefaultRollbackFalseTransactionalSpringRunnerTests extends public class RollbackOverrideDefaultRollbackFalseTransactionalTests extends
DefaultRollbackFalseTransactionalSpringRunnerTests { 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 @Before
@Override @Override
public void verifyInitialTestData() { public void verifyInitialTestData() {
@ -75,6 +69,12 @@ public class RollbackOverrideDefaultRollbackFalseTransactionalSpringRunnerTests
countRowsInPersonTable(jdbcTemplate)); 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 { 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.jdbc.core.JdbcTemplate;
import org.springframework.test.annotation.Rollback; import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.springframework.transaction.annotation.Transactional;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import static org.springframework.test.transaction.TransactionTestUtils.*; 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 * tests method-level <em>rollback override</em> behavior via the
* {@link Rollback @Rollback} annotation. * {@link Rollback @Rollback} annotation.
* *
@ -41,20 +40,14 @@ import static org.springframework.test.transaction.TransactionTestUtils.*;
* @see Rollback * @see Rollback
*/ */
@ContextConfiguration @ContextConfiguration
public class RollbackOverrideDefaultRollbackTrueTransactionalSpringRunnerTests extends public class RollbackOverrideDefaultRollbackTrueTransactionalTests extends
DefaultRollbackTrueTransactionalSpringRunnerTests { 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 @Before
@Override
public void verifyInitialTestData() { public void verifyInitialTestData() {
clearPersonTable(jdbcTemplate); clearPersonTable(jdbcTemplate);
assertEquals("Adding bob", 1, addPerson(jdbcTemplate, BOB)); assertEquals("Adding bob", 1, addPerson(jdbcTemplate, BOB));
@ -62,10 +55,9 @@ public class RollbackOverrideDefaultRollbackTrueTransactionalSpringRunnerTests e
countRowsInPersonTable(jdbcTemplate)); countRowsInPersonTable(jdbcTemplate));
} }
@Override
@Test @Test
@Transactional
@Rollback(false) @Rollback(false)
@Override
public void modifyTestDataWithinTransaction() { public void modifyTestDataWithinTransaction() {
assertInTransaction(true); assertInTransaction(true);
assertEquals("Adding jane", 1, addPerson(jdbcTemplate, JANE)); assertEquals("Adding jane", 1, addPerson(jdbcTemplate, JANE));
@ -74,6 +66,12 @@ public class RollbackOverrideDefaultRollbackTrueTransactionalSpringRunnerTests e
countRowsInPersonTable(jdbcTemplate)); 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 { 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 * <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 * 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 * @author Sam Brannen
* @since 2.5 * @since 2.5
@ -104,10 +104,10 @@ StandardJUnit4FeaturesTests.class,//
ConcreteTransactionalJUnit4SpringContextTests.class,// ConcreteTransactionalJUnit4SpringContextTests.class,//
ClassLevelTransactionalSpringRunnerTests.class,// ClassLevelTransactionalSpringRunnerTests.class,//
MethodLevelTransactionalSpringRunnerTests.class,// MethodLevelTransactionalSpringRunnerTests.class,//
DefaultRollbackTrueTransactionalSpringRunnerTests.class,// DefaultRollbackTrueTransactionalTests.class,//
DefaultRollbackFalseTransactionalSpringRunnerTests.class,// DefaultRollbackFalseTransactionalTests.class,//
RollbackOverrideDefaultRollbackTrueTransactionalSpringRunnerTests.class,// RollbackOverrideDefaultRollbackTrueTransactionalTests.class,//
RollbackOverrideDefaultRollbackFalseTransactionalSpringRunnerTests.class,// RollbackOverrideDefaultRollbackFalseTransactionalTests.class,//
BeforeAndAfterTransactionAnnotationTests.class,// BeforeAndAfterTransactionAnnotationTests.class,//
TimedTransactionalSpringRunnerTests.class,// TimedTransactionalSpringRunnerTests.class,//
ProgrammaticTxMgmtTests.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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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 java.lang.annotation.RetentionPolicy;
import org.junit.After; import org.junit.After;
import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.BDDMockito; import org.mockito.BDDMockito;
import org.springframework.core.annotation.AliasFor;
import org.springframework.test.annotation.Rollback; import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.TestContext; import org.springframework.test.context.TestContext;
import org.springframework.transaction.PlatformTransactionManager; 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.annotation.Transactional;
import org.springframework.transaction.support.SimpleTransactionStatus; import org.springframework.transaction.support.SimpleTransactionStatus;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import static org.mockito.BDDMockito.*; import static org.mockito.BDDMockito.*;
import static org.springframework.transaction.annotation.Propagation.*; import static org.springframework.transaction.annotation.Propagation.*;
@ -41,6 +47,7 @@ import static org.springframework.transaction.annotation.Propagation.*;
* @author Sam Brannen * @author Sam Brannen
* @since 4.0 * @since 4.0
*/ */
@SuppressWarnings("deprecation")
public class TransactionalTestExecutionListenerTests { public class TransactionalTestExecutionListenerTests {
private final PlatformTransactionManager tm = mock(PlatformTransactionManager.class); private final PlatformTransactionManager tm = mock(PlatformTransactionManager.class);
@ -54,6 +61,9 @@ public class TransactionalTestExecutionListenerTests {
private final TestContext testContext = mock(TestContext.class); private final TestContext testContext = mock(TestContext.class);
@Rule
public ExpectedException exception = ExpectedException.none();
private void assertBeforeTestMethod(Class<? extends Invocable> clazz) throws Exception { private void assertBeforeTestMethod(Class<? extends Invocable> clazz) throws Exception {
assertBeforeTestMethodWithTransactionalTestMethod(clazz); assertBeforeTestMethodWithTransactionalTestMethod(clazz);
@ -228,24 +238,86 @@ public class TransactionalTestExecutionListenerTests {
"overriddenTxMgr", true); "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 @Test
public void isRollbackWithMissingRollback() throws Exception { public void isRollbackWithMissingRollback() throws Exception {
assertIsRollback(MissingRollbackTestCase.class, true); assertIsRollback(MissingRollbackTestCase.class, true);
} }
@Test @Test
public void isRollbackWithEmptyRollback() throws Exception { public void isRollbackWithEmptyMethodLevelRollback() throws Exception {
assertIsRollback(EmptyRollbackTestCase.class, true); assertIsRollback(EmptyMethodLevelRollbackTestCase.class, true);
} }
@Test @Test
public void isRollbackWithExplicitValue() throws Exception { public void isRollbackWithMethodLevelRollbackWithExplicitValue() throws Exception {
assertIsRollback(RollbackWithExplicitValueTestCase.class, false); assertIsRollback(MethodLevelRollbackWithExplicitValueTestCase.class, false);
} }
@Test @Test
public void isRollbackViaMetaAnnotation() throws Exception { public void isRollbackWithMethodLevelRollbackViaMetaAnnotation() throws Exception {
assertIsRollback(RollbackViaMetaAnnotationTestCase.class, false); 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) @Retention(RetentionPolicy.RUNTIME)
private static @interface MetaTxWithOverride { private static @interface MetaTxWithOverride {
@AliasFor(annotation = Transactional.class, attribute = "value")
String transactionManager() default "";
Propagation propagation() default REQUIRED; Propagation propagation() default REQUIRED;
} }
@ -467,31 +542,76 @@ public class TransactionalTestExecutionListenerTests {
static class TransactionConfigurationViaMetaAnnotationWithOverrideTestCase { 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 { static class MissingRollbackTestCase {
public void test() { public void test() {
} }
} }
static class EmptyRollbackTestCase { static class EmptyMethodLevelRollbackTestCase {
@Rollback @Rollback
public void test() { public void test() {
} }
} }
static class RollbackWithExplicitValueTestCase { static class MethodLevelRollbackWithExplicitValueTestCase {
@Rollback(false) @Rollback(false)
public void test() { public void test() {
} }
} }
static class RollbackViaMetaAnnotationTestCase { static class MethodLevelRollbackViaMetaAnnotationTestCase {
@Commit @Commit
public void test() { 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" /> p:data-source-ref="dataSource" />
<bean id="databaseSetup" <bean id="databaseSetup"
class="org.springframework.test.context.junit4.DefaultRollbackFalseTransactionalSpringRunnerTests$DatabaseSetup" /> class="org.springframework.test.context.junit4.DefaultRollbackFalseTransactionalTests$DatabaseSetup" />
</beans> </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"> xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="databaseSetup" <bean id="databaseSetup"
class="org.springframework.test.context.junit4.DefaultRollbackTrueTransactionalSpringRunnerTests$DatabaseSetup" /> class="org.springframework.test.context.junit4.DefaultRollbackTrueTransactionalTests$DatabaseSetup" />
</beans> </beans>

View File

@ -10,6 +10,6 @@
p:data-source-ref="dataSource" /> p:data-source-ref="dataSource" />
<bean id="databaseSetup" <bean id="databaseSetup"
class="org.springframework.test.context.junit4.RollbackOverrideDefaultRollbackFalseTransactionalSpringRunnerTests$DatabaseSetup" /> class="org.springframework.test.context.junit4.RollbackOverrideDefaultRollbackFalseTransactionalTests$DatabaseSetup" />
</beans> </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"> xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="databaseSetup" <bean id="databaseSetup"
class="org.springframework.test.context.junit4.RollbackOverrideDefaultRollbackTrueTransactionalSpringRunnerTests$DatabaseSetup" /> class="org.springframework.test.context.junit4.RollbackOverrideDefaultRollbackTrueTransactionalTests$DatabaseSetup" />
</beans> </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 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 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 instructed to cause the transaction to commit instead of roll back via the
<<integration-testing-annotations, `@TransactionConfiguration`>> and <<integration-testing-annotations, `@Rollback`>> annotation.
<<integration-testing-annotations, `@Rollback`>> annotations.
See transaction management with the <<testcontext-tx,TestContext framework>>. 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 `@TestExecutionListeners` supports __inherited__ listeners by default. See the javadocs
for an example and further details. 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` * `@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; 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 otherwise, the transaction is committed.
rollback flag configured at the class level.
+
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` * `@Transactional`
* `@BeforeTransaction` * `@BeforeTransaction`
* `@AfterTransaction` * `@AfterTransaction`
* `@TransactionConfiguration`
* `@Rollback` * `@Rollback`
* `@Sql` * `@Sql`
* `@SqlConfig` * `@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 you wish to reference a base resource path from the classpath instead of the file
system, just use Spring's __classpath:__ prefix. system, just use Spring's __classpath:__ prefix.
Please note that Spring's testing support for `WebApplicationContexts` is on par with Please note that Spring's testing support for `WebApplicationContexts` is on par with its
its support for standard `ApplicationContexts`. When testing with a support for standard `ApplicationContexts`. When testing with a `WebApplicationContext`
`WebApplicationContext` you are free to declare either XML configuration files or you are free to declare XML configuration files, Groovy scripts, or `@Configuration`
`@Configuration` classes via `@ContextConfiguration`. You are of course also free to use classes via `@ContextConfiguration`. You are of course also free to use any other test
any other test annotations such as `@TestExecutionListeners`, annotations such as `@ActiveProfiles`, `@TestExecutionListeners`, `@Sql`, `@Rollback`,
`@TransactionConfiguration`, `@ActiveProfiles`, etc. etc.
The following examples demonstrate some of the various configuration options for loading The following examples demonstrate some of the various configuration options for loading
a `WebApplicationContext`. 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 By default, test transactions will be automatically rolled back after completion of the
test; however, transactional commit and rollback behavior can be configured declaratively test; however, transactional commit and rollback behavior can be configured declaratively
via the class-level `@TransactionConfiguration` and method-level `@Rollback` annotations. via the `@Rollback` annotation. See the corresponding entry in the
See the corresponding entries in the <<integration-testing-annotations,annotation <<integration-testing-annotations,annotation support>> section for further details.
support>> section for further details.
[[testcontext-tx-programmatic-tx-mgt]] [[testcontext-tx-programmatic-tx-mgt]]
===== Programmatic transaction management ===== Programmatic transaction management
@ -3224,14 +3190,12 @@ to run within a transaction.
`TransactionalTestExecutionListener` expects a `PlatformTransactionManager` bean to be `TransactionalTestExecutionListener` expects a `PlatformTransactionManager` bean to be
defined in the Spring `ApplicationContext` for the test. In case there are multiple defined in the Spring `ApplicationContext` for the test. In case there are multiple
instances of `PlatformTransactionManager` within the test's `ApplicationContext`, instances of `PlatformTransactionManager` within the test's `ApplicationContext`, a
`@TransactionConfiguration` supports configuring the bean name of the _qualifier_ may be declared via `@Transactional("myTxMgr")` or
`PlatformTransactionManager` that should be used to drive transactions. Alternatively, a `@Transactional(transactionManager = "myTxMgr")`, or `TransactionManagementConfigurer`
_qualifier_ may be declared via `@Transactional("myQualifier")`, or can be implemented by an `@Configuration` class. Consult the javadocs for
`TransactionManagementConfigurer` can be implemented by an `@Configuration` class. `TestContextTransactionUtils.retrieveTransactionManager()` for details on the algorithm
Consult the javadocs for `TestContextTransactionUtils.retrieveTransactionManager()` for used to look up a transaction manager in the test's `ApplicationContext`.
details on the algorithm used to look up a transaction manager in the test's
`ApplicationContext`.
[[testcontext-tx-annotation-demo]] [[testcontext-tx-annotation-demo]]
===== Demonstration of all transaction-related annotations ===== Demonstration of all transaction-related annotations
@ -3249,8 +3213,8 @@ declarative SQL script execution with default transaction rollback semantics.
---- ----
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration @ContextConfiguration
**@TransactionConfiguration(transactionManager="txMgr", defaultRollback=false) @Transactional(transactionManager = "txMgr")
@Transactional** **@Rollback(false)**
public class FictitiousTransactionalTest { public class FictitiousTransactionalTest {
**@BeforeTransaction** **@BeforeTransaction**
@ -3264,7 +3228,7 @@ declarative SQL script execution with default transaction rollback semantics.
} }
@Test @Test
// overrides the class-level defaultRollback setting // overrides the class-level default rollback setting
**@Rollback(true)** **@Rollback(true)**
public void modifyDatabaseWithinTransaction() { public void modifyDatabaseWithinTransaction() {
// logic which uses the test data and modifies database state // 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 _before_ a test -- for example, if some rogue (i.e., yet to be
determined) test within a large test suite has corrupted the original determined) test within a large test suite has corrupted the original
configuration for the `ApplicationContext`. 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 * `@Sql` now supports execution of _inlined SQL statements_ via a new
`statements` attribute. `statements` attribute.
* The `ContextCache` that is used for caching ++ApplicationContext++s * The `ContextCache` that is used for caching ++ApplicationContext++s