diff --git a/spring-test/src/main/java/org/springframework/test/context/transaction/TransactionConfiguration.java b/spring-test/src/main/java/org/springframework/test/context/transaction/TransactionConfiguration.java
index c2c72c7c3444d4bf805cf633e936fb2d800ee122..e62317b783a84f8906bb4174f117d24b3daf2a2f 100644
--- a/spring-test/src/main/java/org/springframework/test/context/transaction/TransactionConfiguration.java
+++ b/spring-test/src/main/java/org/springframework/test/context/transaction/TransactionConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-2012 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,17 +23,14 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-import org.springframework.test.context.ContextConfiguration;
-import org.springframework.transaction.PlatformTransactionManager;
-
/**
- * TransactionConfiguration defines class-level metadata for configuring
+ * {@code TransactionConfiguration} defines class-level metadata for configuring
* transactional tests.
*
* @author Sam Brannen
* @since 2.5
- * @see ContextConfiguration
* @see TransactionalTestExecutionListener
+ * @see org.springframework.test.context.ContextConfiguration
*/
@Documented
@Inherited
@@ -42,15 +39,19 @@ import org.springframework.transaction.PlatformTransactionManager;
public @interface TransactionConfiguration {
/**
- * The bean name of the {@link PlatformTransactionManager} that is to be
- * used to drive transactions. This attribute is not required and only needs
- * to be specified explicitly if the bean name of the desired
- * PlatformTransactionManager is not "transactionManager".
- *
NOTE: The XML <tx:annotation-driven> element
- * also refers to a bean named "transactionManager" by default. If you are
- * using both features in combination, make sure to point to the same
- * transaction manager bean - here in @TransactionConfiguration and
- * also in <tx:annotation-driven transaction-manager="...">.
+ * The bean name of the {@link org.springframework.transaction.PlatformTransactionManager
+ * PlatformTransactionManager} that is to be used to drive transactions.
+ *
+ *
This attribute is not required and only needs to be specified explicitly
+ * if there are multiple beans of type {@code PlatformTransactionManager} in
+ * the test's {@code ApplicationContext} and the bean name of the desired
+ * {@code PlatformTransactionManager} is not "transactionManager".
+ *
+ *
NOTE: The XML {@code } element also refers
+ * to a bean named "transactionManager" by default. If you are using both
+ * features in combination, make sure to point to the same transaction manager
+ * bean - here in {@code @TransactionConfiguration} and also in
+ * {@code }.
*/
String transactionManager() default "transactionManager";
diff --git a/spring-test/src/main/java/org/springframework/test/context/transaction/TransactionalTestExecutionListener.java b/spring-test/src/main/java/org/springframework/test/context/transaction/TransactionalTestExecutionListener.java
index 2e533ad4638544937bcbdc93bd827f89b8fffe98..e182259ba726d1aebf33187be6063eb856b8e296 100644
--- a/spring-test/src/main/java/org/springframework/test/context/transaction/TransactionalTestExecutionListener.java
+++ b/spring-test/src/main/java/org/springframework/test/context/transaction/TransactionalTestExecutionListener.java
@@ -19,7 +19,6 @@ package org.springframework.test.context.transaction;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-
import java.util.ArrayList;
import java.util.Collections;
import java.util.IdentityHashMap;
@@ -30,7 +29,10 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryUtils;
+import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils;
+import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.test.annotation.NotTransactional;
import org.springframework.test.annotation.Rollback;
@@ -49,37 +51,35 @@ import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
/**
- *
- * TestExecutionListener that provides support for executing
- * tests within transactions by using the
+ * {@code TestExecutionListener} that provides support for executing tests
+ * within transactions by honoring the
* {@link org.springframework.transaction.annotation.Transactional @Transactional}
- * and {@link NotTransactional @NotTransactional} annotations.
- *
- *
- * Changes to the database during a test that is run with @Transactional will be
- * run within a transaction that will, by default, be automatically
+ * and {@link NotTransactional @NotTransactional} annotations. Expects a
+ * {@link PlatformTransactionManager} bean to be defined in the Spring
+ * {@link ApplicationContext} for the test.
+ *
+ *
Changes to the database during a test that is run with {@code @Transactional}
+ * will be run within a transaction that will, by default, be automatically
* rolled back after completion of the test; whereas, changes to the
- * database during a test that is run with @NotTransactional will not
- * be run within a transaction. Test methods that are not annotated with either
- * @Transactional (at the class or method level) or @NotTransactional
- * will not be run within a transaction.
- *
- *
- * Transactional commit and rollback behavior can be configured via the
- * class-level {@link TransactionConfiguration @TransactionConfiguration} and
- * method-level {@link Rollback @Rollback} annotations.
- * {@link TransactionConfiguration @TransactionConfiguration} also provides
- * configuration of the bean name of the {@link PlatformTransactionManager} that
- * is to be used to drive transactions.
- *
- *
- * When executing transactional tests, it is sometimes useful to be able to execute
- * certain set up or tear down code outside of a
- * transaction. TransactionalTestExecutionListener provides such
+ * database during a test that is run with {@code @NotTransactional} will
+ * not be run within a transaction. Test methods that are not
+ * annotated with either {@code @Transactional} (at the class or method level)
+ * or {@code @NotTransactional} will not be run within a transaction.
+ *
+ *
Transactional commit and rollback behavior can be configured via the
+ * class-level {@link TransactionConfiguration @TransactionConfiguration} and
+ * method-level {@link Rollback @Rollback} annotations. 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 is
+ * to be used to drive transactions.
+ *
+ *
When executing transactional tests, it is sometimes useful to be able to
+ * execute certain set up or tear down code outside of a
+ * transaction. {@code TransactionalTestExecutionListener} provides such
* support for methods annotated with
- * {@link BeforeTransaction @BeforeTransaction} and
- * {@link AfterTransaction @AfterTransaction}.
- *
+ * {@link BeforeTransaction @BeforeTransaction} and
+ * {@link AfterTransaction @AfterTransaction}.
*
* @author Sam Brannen
* @author Juergen Hoeller
@@ -96,25 +96,33 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
private static final Log logger = LogFactory.getLog(TransactionalTestExecutionListener.class);
+ private static final String DEFAULT_TRANSACTION_MANAGER_NAME = (String) AnnotationUtils.getDefaultValue(
+ TransactionConfiguration.class, "transactionManager");
+
+ private static final Boolean DEFAULT_DEFAULT_ROLLBACK = (Boolean) AnnotationUtils.getDefaultValue(
+ TransactionConfiguration.class, "defaultRollback");
+
protected final TransactionAttributeSource attributeSource = new AnnotationTransactionAttributeSource();
+ private final Map transactionContextCache =
+ Collections.synchronizedMap(new IdentityHashMap());
+
private TransactionConfigurationAttributes configurationAttributes;
private volatile int transactionsStarted = 0;
- private final Map transactionContextCache = Collections.synchronizedMap(new IdentityHashMap());
-
/**
* If the test method of the supplied {@link TestContext test context} is
* configured to run within a transaction, this method will run
* {@link BeforeTransaction @BeforeTransaction methods} and start a new
* transaction.
- *
Note that if a {@link BeforeTransaction @BeforeTransaction method} fails,
- * remaining {@link BeforeTransaction @BeforeTransaction methods} will not
+ *
Note that if a {@code BeforeTransaction @BeforeTransaction method} fails,
+ * remaining {@code BeforeTransaction @BeforeTransaction methods} will not
* be invoked, and a transaction will not be started.
* @see org.springframework.transaction.annotation.Transactional
* @see org.springframework.test.annotation.NotTransactional
+ * @see #getTransactionManager(TestContext, String)
*/
@SuppressWarnings("serial")
@Override
@@ -131,36 +139,27 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
return;
}
+ PlatformTransactionManager tm = null;
TransactionAttribute transactionAttribute = this.attributeSource.getTransactionAttribute(testMethod,
testContext.getTestClass());
- TransactionDefinition transactionDefinition = null;
+
if (transactionAttribute != null) {
- transactionDefinition = new DelegatingTransactionAttribute(transactionAttribute) {
+ transactionAttribute = new DelegatingTransactionAttribute(transactionAttribute) {
public String getName() {
return testMethod.getName();
}
};
- }
- if (transactionDefinition != null) {
if (logger.isDebugEnabled()) {
- logger.debug("Explicit transaction definition [" + transactionDefinition + "] found for test context ["
- + testContext + "]");
+ logger.debug("Explicit transaction definition [" + transactionAttribute + "] found for test context "
+ + testContext);
}
- String qualifier = transactionAttribute.getQualifier();
- PlatformTransactionManager tm;
- if (StringUtils.hasLength(qualifier)) {
- // Use autowire-capable factory in order to support extended
- // qualifier matching (only exposed on the internal BeanFactory,
- // not on the ApplicationContext).
- BeanFactory bf = testContext.getApplicationContext().getAutowireCapableBeanFactory();
- tm = BeanFactoryAnnotationUtils.qualifiedBeanOfType(bf, PlatformTransactionManager.class, qualifier);
- }
- else {
- tm = getTransactionManager(testContext);
- }
- TransactionContext txContext = new TransactionContext(tm, transactionDefinition);
+ tm = getTransactionManager(testContext, transactionAttribute.getQualifier());
+ }
+
+ if (tm != null) {
+ TransactionContext txContext = new TransactionContext(tm, transactionAttribute);
runBeforeTransactionMethods(testContext);
startNewTransaction(testContext, txContext);
this.transactionContextCache.put(testMethod, txContext);
@@ -171,7 +170,7 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
* If a transaction is currently active for the test method of the supplied
* {@link TestContext test context}, this method will end the transaction
* and run {@link AfterTransaction @AfterTransaction methods}.
- *
{@link AfterTransaction @AfterTransaction methods} are guaranteed to be
+ *
{@code AfterTransaction @AfterTransaction methods} are guaranteed to be
* invoked even if an error occurs while ending the transaction.
*/
@Override
@@ -205,15 +204,14 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
Collections.reverse(methods);
for (Method method : methods) {
if (logger.isDebugEnabled()) {
- logger.debug("Executing @BeforeTransaction method [" + method + "] for test context ["
- + testContext + "]");
+ logger.debug("Executing @BeforeTransaction method [" + method + "] for test context " + testContext);
}
method.invoke(testContext.getTestInstance());
}
}
catch (InvocationTargetException ex) {
- logger.error("Exception encountered while executing @BeforeTransaction methods for test context ["
- + testContext + "]", ex.getTargetException());
+ logger.error("Exception encountered while executing @BeforeTransaction methods for test context "
+ + testContext + ".", ex.getTargetException());
ReflectionUtils.rethrowException(ex.getTargetException());
}
}
@@ -233,8 +231,7 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
for (Method method : methods) {
try {
if (logger.isDebugEnabled()) {
- logger.debug("Executing @AfterTransaction method [" + method + "] for test context [" + testContext
- + "]");
+ logger.debug("Executing @AfterTransaction method [" + method + "] for test context " + testContext);
}
method.invoke(testContext.getTestInstance());
}
@@ -244,14 +241,14 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
afterTransactionException = targetException;
}
logger.error("Exception encountered while executing @AfterTransaction method [" + method
- + "] for test context [" + testContext + "]", targetException);
+ + "] for test context " + testContext, targetException);
}
catch (Exception ex) {
if (afterTransactionException == null) {
afterTransactionException = ex;
}
logger.error("Exception encountered while executing @AfterTransaction method [" + method
- + "] for test context [" + testContext + "]", ex);
+ + "] for test context " + testContext, ex);
}
}
@@ -287,14 +284,50 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
private void endTransaction(TestContext testContext, TransactionContext txContext) throws Exception {
boolean rollback = isRollback(testContext);
if (logger.isTraceEnabled()) {
- logger.trace("Ending transaction for test context [" + testContext + "]; transaction manager ["
+ logger.trace("Ending transaction for test context " + testContext + "; transaction manager ["
+ txContext.transactionStatus + "]; rollback [" + rollback + "]");
}
txContext.endTransaction(rollback);
if (logger.isInfoEnabled()) {
logger.info((rollback ? "Rolled back" : "Committed")
- + " transaction after test execution for test context [" + testContext + "]");
+ + " transaction after test execution for test context " + testContext);
+ }
+ }
+
+ /**
+ * Get the {@link PlatformTransactionManager transaction manager} to use
+ * for the supplied {@link TestContext test context} and {@code qualifier}.
+ *
Delegates to {@link #getTransactionManager(TestContext)} if the
+ * supplied {@code qualifier} is null or empty.
+ * @param testContext the test context for which the transaction manager
+ * should be retrieved
+ * @param qualifier the qualifier for selecting between multiple bean matches;
+ * may be null or empty
+ * @return the transaction manager to use, or null if not found
+ * @throws BeansException if an error occurs while retrieving the transaction manager
+ * @see #getTransactionManager(TestContext)
+ */
+ protected final PlatformTransactionManager getTransactionManager(TestContext testContext, String qualifier) {
+ // look up by type and qualifier from @Transactional
+ if (StringUtils.hasText(qualifier)) {
+ try {
+ // Use autowire-capable factory in order to support extended qualifier
+ // matching (only exposed on the internal BeanFactory, not on the
+ // ApplicationContext).
+ BeanFactory bf = testContext.getApplicationContext().getAutowireCapableBeanFactory();
+
+ return BeanFactoryAnnotationUtils.qualifiedBeanOfType(bf, PlatformTransactionManager.class, qualifier);
+ } catch (RuntimeException ex) {
+ if (logger.isWarnEnabled()) {
+ logger.warn("Caught exception while retrieving transaction manager for test context " + testContext
+ + " and qualifier [" + qualifier + "]", ex);
+ }
+ throw ex;
+ }
}
+
+ // else
+ return getTransactionManager(testContext);
}
/**
@@ -304,16 +337,34 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
* should be retrieved
* @return the transaction manager to use, or null if not found
* @throws BeansException if an error occurs while retrieving the transaction manager
+ * @see #getTransactionManager(TestContext, String)
*/
protected final PlatformTransactionManager getTransactionManager(TestContext testContext) {
+ BeanFactory bf = testContext.getApplicationContext().getAutowireCapableBeanFactory();
String tmName = retrieveConfigurationAttributes(testContext).getTransactionManagerName();
+
try {
- return testContext.getApplicationContext().getBean(tmName, PlatformTransactionManager.class);
- }
- catch (BeansException ex) {
+ // look up by type and explicit name from @TransactionConfiguration
+ if (StringUtils.hasText(tmName) && !DEFAULT_TRANSACTION_MANAGER_NAME.equals(tmName)) {
+ return bf.getBean(tmName, PlatformTransactionManager.class);
+ }
+
+ // look up single bean by type
+ if (bf instanceof ListableBeanFactory) {
+ ListableBeanFactory lbf = (ListableBeanFactory) bf;
+ Map beansOfType = BeanFactoryUtils.beansOfTypeIncludingAncestors(
+ lbf, PlatformTransactionManager.class);
+ if (beansOfType.size() == 1) {
+ return beansOfType.values().iterator().next();
+ }
+ }
+
+ // look up by type and default name from @TransactionConfiguration
+ return bf.getBean(DEFAULT_TRANSACTION_MANAGER_NAME, PlatformTransactionManager.class);
+
+ } catch (BeansException ex) {
if (logger.isWarnEnabled()) {
- logger.warn("Caught exception while retrieving transaction manager with bean name [" + tmName
- + "] for test context [" + testContext + "]", ex);
+ logger.warn("Caught exception while retrieving transaction manager for test context " + testContext, ex);
}
throw ex;
}
@@ -348,14 +399,14 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
boolean rollbackOverride = rollbackAnnotation.value();
if (logger.isDebugEnabled()) {
logger.debug("Method-level @Rollback(" + rollbackOverride + ") overrides default rollback [" + rollback
- + "] for test context [" + testContext + "]");
+ + "] for test context " + testContext);
}
rollback = rollbackOverride;
}
else {
if (logger.isDebugEnabled()) {
logger.debug("No method-level @Rollback override: using default rollback [" + rollback
- + "] for test context [" + testContext + "]");
+ + "] for test context " + testContext);
}
}
return rollback;
@@ -451,20 +502,19 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
/**
* Retrieves the {@link TransactionConfigurationAttributes} for the
- * specified {@link Class class} which may optionally declare or inherit a
- * {@link TransactionConfiguration @TransactionConfiguration}. If a
- * {@link TransactionConfiguration} annotation is not present for the
- * supplied class, the default values for attributes defined in
- * {@link TransactionConfiguration} will be used instead.
- * @param clazz the Class object corresponding to the test class for which
- * the configuration attributes should be retrieved
+ * specified {@link Class class} which may optionally declare or inherit
+ * {@link TransactionConfiguration @TransactionConfiguration}. If
+ * {@code @TransactionConfiguration} is not present for the supplied
+ * class, the default values for attributes defined in
+ * {@code @TransactionConfiguration} will be used instead.
+ * @param testContext the test context for which the configuration
+ * attributes should be retrieved
* @return a new TransactionConfigurationAttributes instance
*/
private TransactionConfigurationAttributes retrieveConfigurationAttributes(TestContext testContext) {
if (this.configurationAttributes == null) {
Class> clazz = testContext.getTestClass();
- Class annotationType = TransactionConfiguration.class;
- TransactionConfiguration config = clazz.getAnnotation(annotationType);
+ TransactionConfiguration config = clazz.getAnnotation(TransactionConfiguration.class);
if (logger.isDebugEnabled()) {
logger.debug("Retrieved @TransactionConfiguration [" + config + "] for test class [" + clazz + "]");
}
@@ -476,14 +526,14 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
defaultRollback = config.defaultRollback();
}
else {
- transactionManagerName = (String) AnnotationUtils.getDefaultValue(annotationType, "transactionManager");
- defaultRollback = (Boolean) AnnotationUtils.getDefaultValue(annotationType, "defaultRollback");
+ transactionManagerName = DEFAULT_TRANSACTION_MANAGER_NAME;
+ defaultRollback = DEFAULT_DEFAULT_ROLLBACK;
}
TransactionConfigurationAttributes configAttributes = new TransactionConfigurationAttributes(
transactionManagerName, defaultRollback);
if (logger.isDebugEnabled()) {
- logger.debug("Retrieved TransactionConfigurationAttributes [" + configAttributes + "] for class ["
+ logger.debug("Retrieved TransactionConfigurationAttributes " + configAttributes + " for class ["
+ clazz + "]");
}
this.configurationAttributes = configAttributes;
diff --git a/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpNonexistentTxMgrTests.java b/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpNonexistentTxMgrTests.java
new file mode 100644
index 0000000000000000000000000000000000000000..0a70b0d0a25c6fd2acfeb788373d622992178abb
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpNonexistentTxMgrTests.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2002-2012 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.spr9645;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.transaction.AfterTransaction;
+import org.springframework.test.context.transaction.BeforeTransaction;
+import org.springframework.test.transaction.CallCountingTransactionManager;
+import org.springframework.transaction.PlatformTransactionManager;
+
+/**
+ * Integration tests that verify the behavior requested in
+ * SPR-9645.
+ *
+ * @author Sam Brannen
+ * @since 3.2
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration
+public class LookUpNonexistentTxMgrTests {
+
+ private static final CallCountingTransactionManager txManager = new CallCountingTransactionManager();
+
+
+ @Configuration
+ static class Config {
+
+ @Bean
+ public PlatformTransactionManager transactionManager() {
+ return txManager;
+ }
+ }
+
+
+ @BeforeTransaction
+ public void beforeTransaction() {
+ txManager.clear();
+ }
+
+ @Test
+ public void lookUpNothing() {
+ assertEquals(0, txManager.begun);
+ assertEquals(0, txManager.inflight);
+ assertEquals(0, txManager.commits);
+ assertEquals(0, txManager.rollbacks);
+ }
+
+ @AfterTransaction
+ public void afterTransaction() {
+ assertEquals(0, txManager.begun);
+ assertEquals(0, txManager.inflight);
+ assertEquals(0, txManager.commits);
+ assertEquals(0, txManager.rollbacks);
+ }
+
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndDefaultNameTests.java b/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndDefaultNameTests.java
new file mode 100644
index 0000000000000000000000000000000000000000..5cfdebaba386e7ed1d548f27c5bb70131e73d5e2
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndDefaultNameTests.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2002-2012 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.spr9645;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.transaction.AfterTransaction;
+import org.springframework.test.context.transaction.BeforeTransaction;
+import org.springframework.test.transaction.CallCountingTransactionManager;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * Integration tests that verify the behavior requested in
+ * SPR-9645.
+ *
+ * @author Sam Brannen
+ * @since 3.2
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration
+@Transactional
+public class LookUpTxMgrByTypeAndDefaultNameTests {
+
+ private static final CallCountingTransactionManager txManager1 = new CallCountingTransactionManager();
+ private static final CallCountingTransactionManager txManager2 = new CallCountingTransactionManager();
+
+ @Configuration
+ static class Config {
+
+ @Bean
+ public PlatformTransactionManager transactionManager() {
+ return txManager1;
+ }
+
+ @Bean
+ public PlatformTransactionManager txManager2() {
+ return txManager2;
+ }
+ }
+
+ @BeforeTransaction
+ public void beforeTransaction() {
+ txManager1.clear();
+ txManager2.clear();
+ }
+
+ @Test
+ public void lookUpByTypeAndDefaultName() {
+ assertEquals(1, txManager1.begun);
+ assertEquals(1, txManager1.inflight);
+ assertEquals(0, txManager1.commits);
+ assertEquals(0, txManager1.rollbacks);
+ }
+
+ @AfterTransaction
+ public void afterTransaction() {
+ assertEquals(1, txManager1.begun);
+ assertEquals(0, txManager1.inflight);
+ assertEquals(0, txManager1.commits);
+ assertEquals(1, txManager1.rollbacks);
+ }
+
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndNameTests.java b/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndNameTests.java
new file mode 100644
index 0000000000000000000000000000000000000000..805243f11c96cd3f8817a3807c3c57084216913e
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndNameTests.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2002-2012 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.spr9645;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.transaction.AfterTransaction;
+import org.springframework.test.context.transaction.BeforeTransaction;
+import org.springframework.test.context.transaction.TransactionConfiguration;
+import org.springframework.test.transaction.CallCountingTransactionManager;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * Integration tests that verify the behavior requested in
+ * SPR-9645.
+ *
+ * @author Sam Brannen
+ * @since 3.2
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration
+@Transactional
+@TransactionConfiguration(transactionManager = "txManager1")
+public class LookUpTxMgrByTypeAndNameTests {
+
+ private static final CallCountingTransactionManager txManager1 = new CallCountingTransactionManager();
+ private static final CallCountingTransactionManager txManager2 = new CallCountingTransactionManager();
+
+ @Configuration
+ static class Config {
+
+ @Bean
+ public PlatformTransactionManager txManager1() {
+ return txManager1;
+ }
+
+ @Bean
+ public PlatformTransactionManager txManager2() {
+ return txManager2;
+ }
+ }
+
+ @BeforeTransaction
+ public void beforeTransaction() {
+ txManager1.clear();
+ txManager2.clear();
+ }
+
+ @Test
+ public void lookUpByTypeAndName() {
+ assertEquals(1, txManager1.begun);
+ assertEquals(1, txManager1.inflight);
+ assertEquals(0, txManager1.commits);
+ assertEquals(0, txManager1.rollbacks);
+ }
+
+ @AfterTransaction
+ public void afterTransaction() {
+ assertEquals(1, txManager1.begun);
+ assertEquals(0, txManager1.inflight);
+ assertEquals(0, txManager1.commits);
+ assertEquals(1, txManager1.rollbacks);
+ }
+
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndQualifierAtClassLevelTests.java b/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndQualifierAtClassLevelTests.java
new file mode 100644
index 0000000000000000000000000000000000000000..cd78baea45d886369acfa31b9c7b30c07dc5b692
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndQualifierAtClassLevelTests.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2002-2012 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.spr9645;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.transaction.AfterTransaction;
+import org.springframework.test.context.transaction.BeforeTransaction;
+import org.springframework.test.transaction.CallCountingTransactionManager;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * Integration tests that verify the behavior requested in
+ * SPR-9645.
+ *
+ * @author Sam Brannen
+ * @since 3.2
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration
+@Transactional("txManager1")
+public class LookUpTxMgrByTypeAndQualifierAtClassLevelTests {
+
+ private static final CallCountingTransactionManager txManager1 = new CallCountingTransactionManager();
+ private static final CallCountingTransactionManager txManager2 = new CallCountingTransactionManager();
+
+ @Configuration
+ static class Config {
+
+ @Bean
+ public PlatformTransactionManager txManager1() {
+ return txManager1;
+ }
+
+ @Bean
+ public PlatformTransactionManager txManager2() {
+ return txManager2;
+ }
+ }
+
+ @BeforeTransaction
+ public void beforeTransaction() {
+ txManager1.clear();
+ txManager2.clear();
+ }
+
+ @Test
+ public void lookUpByTypeAndQualifier() {
+ assertEquals(1, txManager1.begun);
+ assertEquals(1, txManager1.inflight);
+ assertEquals(0, txManager1.commits);
+ assertEquals(0, txManager1.rollbacks);
+ }
+
+ @AfterTransaction
+ public void afterTransaction() {
+ assertEquals(1, txManager1.begun);
+ assertEquals(0, txManager1.inflight);
+ assertEquals(0, txManager1.commits);
+ assertEquals(1, txManager1.rollbacks);
+ }
+
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndQualifierAtMethodLevelTests.java b/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndQualifierAtMethodLevelTests.java
new file mode 100644
index 0000000000000000000000000000000000000000..0a9335dbcaad1b39d0b8942b1f585b2afa1a1170
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndQualifierAtMethodLevelTests.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2002-2012 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.spr9645;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.transaction.AfterTransaction;
+import org.springframework.test.context.transaction.BeforeTransaction;
+import org.springframework.test.transaction.CallCountingTransactionManager;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * Integration tests that verify the behavior requested in
+ * SPR-9645.
+ *
+ * @author Sam Brannen
+ * @since 3.2
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration
+public class LookUpTxMgrByTypeAndQualifierAtMethodLevelTests {
+
+ private static final CallCountingTransactionManager txManager1 = new CallCountingTransactionManager();
+ private static final CallCountingTransactionManager txManager2 = new CallCountingTransactionManager();
+
+ @Configuration
+ static class Config {
+
+ @Bean
+ public PlatformTransactionManager txManager1() {
+ return txManager1;
+ }
+
+ @Bean
+ public PlatformTransactionManager txManager2() {
+ return txManager2;
+ }
+ }
+
+ @BeforeTransaction
+ public void beforeTransaction() {
+ txManager1.clear();
+ txManager2.clear();
+ }
+
+ @Transactional("txManager1")
+ @Test
+ public void lookUpByTypeAndQualifier() {
+ assertEquals(1, txManager1.begun);
+ assertEquals(1, txManager1.inflight);
+ assertEquals(0, txManager1.commits);
+ assertEquals(0, txManager1.rollbacks);
+ }
+
+ @AfterTransaction
+ public void afterTransaction() {
+ assertEquals(1, txManager1.begun);
+ assertEquals(0, txManager1.inflight);
+ assertEquals(0, txManager1.commits);
+ assertEquals(1, txManager1.rollbacks);
+ }
+
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeTests.java b/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeTests.java
new file mode 100644
index 0000000000000000000000000000000000000000..ed4847980585c2394ee6ea2b349d0d34482c4476
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeTests.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2002-2012 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.spr9645;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.transaction.AfterTransaction;
+import org.springframework.test.context.transaction.BeforeTransaction;
+import org.springframework.test.transaction.CallCountingTransactionManager;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * Integration tests that verify the behavior requested in
+ * SPR-9645.
+ *
+ * @author Sam Brannen
+ * @since 3.2
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration
+@Transactional
+public class LookUpTxMgrByTypeTests {
+
+ private static final CallCountingTransactionManager txManager = new CallCountingTransactionManager();
+
+ @Configuration
+ static class Config {
+
+ @Bean
+ public PlatformTransactionManager txManager() {
+ return txManager;
+ }
+ }
+
+ @BeforeTransaction
+ public void beforeTransaction() {
+ txManager.clear();
+ }
+
+ @Test
+ public void lookUpByType() {
+ assertEquals(1, txManager.begun);
+ assertEquals(1, txManager.inflight);
+ assertEquals(0, txManager.commits);
+ assertEquals(0, txManager.rollbacks);
+ }
+
+ @AfterTransaction
+ public void afterTransaction() {
+ assertEquals(1, txManager.begun);
+ assertEquals(0, txManager.inflight);
+ assertEquals(0, txManager.commits);
+ assertEquals(1, txManager.rollbacks);
+ }
+
+}
diff --git a/spring-test/src/test/java/org/springframework/test/transaction/CallCountingTransactionManager.java b/spring-test/src/test/java/org/springframework/test/transaction/CallCountingTransactionManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..8713dbe5ee652f275aa8baf59f57d954cb904769
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/transaction/CallCountingTransactionManager.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2002-2012 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.transaction;
+
+import org.springframework.transaction.TransactionDefinition;
+import org.springframework.transaction.support.AbstractPlatformTransactionManager;
+import org.springframework.transaction.support.DefaultTransactionStatus;
+
+/**
+ * @author Rod Johnson
+ * @author Juergen Hoeller
+ */
+@SuppressWarnings("serial")
+public class CallCountingTransactionManager extends AbstractPlatformTransactionManager {
+
+ public TransactionDefinition lastDefinition;
+ public int begun;
+ public int commits;
+ public int rollbacks;
+ public int inflight;
+
+
+ protected Object doGetTransaction() {
+ return new Object();
+ }
+
+ protected void doBegin(Object transaction, TransactionDefinition definition) {
+ this.lastDefinition = definition;
+ ++begun;
+ ++inflight;
+ }
+
+ protected void doCommit(DefaultTransactionStatus status) {
+ ++commits;
+ --inflight;
+ }
+
+ protected void doRollback(DefaultTransactionStatus status) {
+ ++rollbacks;
+ --inflight;
+ }
+
+ public void clear() {
+ begun = commits = rollbacks = inflight = 0;
+ }
+
+}
diff --git a/spring-test/src/test/resources/log4j.xml b/spring-test/src/test/resources/log4j.xml
index bcfcb8f81af19ad59abe04dec0d6b5e691d482e0..873d2ccdc45707d54c5566dbf1136df2c1eb3d45 100644
--- a/spring-test/src/test/resources/log4j.xml
+++ b/spring-test/src/test/resources/log4j.xml
@@ -41,6 +41,10 @@
-->
+
+
+
+
diff --git a/src/dist/changelog.txt b/src/dist/changelog.txt
index d5406a535f676f365219e6f3132899465f61bea6..4c8f1c6443458b13529f029f8411226efbe46dce 100644
--- a/src/dist/changelog.txt
+++ b/src/dist/changelog.txt
@@ -28,6 +28,7 @@ Changes in version 3.2 M2 (2012-08-xx)
* add exclude patterns for mapped interceptors in MVC namespace and MVC Java config
* support content negotiation options in MVC namespace and MVC Java config
* support named dispatchers in MockServletContext (SPR-9587)
+* support single, unqualified tx manager in the TestContext framework (SPR-9645)
Changes in version 3.2 M1 (2012-05-28)
diff --git a/src/reference/docbook/testing.xml b/src/reference/docbook/testing.xml
index 1af3b663f4b966958731d49729d079281f206b00..0f8a4bf064aa0e4fb0fdd1b502fa47b266e2cf1d 100644
--- a/src/reference/docbook/testing.xml
+++ b/src/reference/docbook/testing.xml
@@ -8,7 +8,7 @@
xmlns:ns="http://docbook.org/ns/docbook">
Testing
-
+ Introduction to Spring TestingTesting is an integral part of enterprise software development. This
@@ -20,7 +20,7 @@
this reference manual.)
-
+ Unit TestingDependency Injection should make your code less dependent on the
@@ -44,10 +44,10 @@
however, the Spring Framework provides the following mock objects and
testing support classes.
-
+ Mock Objects
-
+ JNDIThe org.springframework.mock.jndi package
@@ -59,20 +59,20 @@
testing scenarios without modification.
-
+ Servlet APIThe org.springframework.mock.web package
contains a comprehensive set of Servlet API mock objects, targeted at
usage with Spring's Web MVC framework, which are useful for testing
web contexts and controllers. These mock objects are generally more
- convenient to use than dynamic mock objects such as EasyMock or existing Servlet API
- mock objects such as MockObjects.
+ convenient to use than dynamic mock objects such as EasyMock or existing
+ Servlet API mock objects such as MockObjects.
-
+ Portlet APIThe org.springframework.mock.web.portlet
@@ -81,10 +81,10 @@
-
+ Unit Testing support Classes
-
+ General utilitiesThe org.springframework.test.util package
@@ -115,7 +115,7 @@
-
+ Spring MVCThe org.springframework.test.web package
@@ -131,18 +131,18 @@
ModelAndViewAssert combined with
MockHttpServletRequest,
MockHttpSession, and so on from the
- org.springframework.mock.web
- package.
+ linkend="mock-objects-servlet">
+ org.springframework.mock.web
+ package.
-
+ Integration Testing
-
+ OverviewIt is important to be able to perform some integration testing
@@ -211,7 +211,7 @@
-
+ Goals of Integration TestingSpring's integration testing support has the following primary
@@ -244,7 +244,7 @@
The next few sections describe each goal and provide links to
implementation and configuration details.
-
+ Context management and cachingThe Spring TestContext Framework provides consistent loading of
@@ -284,7 +284,7 @@
framework.
-
+ Dependency Injection of test fixturesWhen the TestContext framework loads your application context,
@@ -328,7 +328,7 @@
linkend="testcontext-fixture-di">TestContext framework.
-
+ Transaction managementOne common issue in tests that access a real database is their
@@ -354,17 +354,16 @@
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
- @TransactionConfiguration
- and
- @Rollback
- annotations.
+ linkend="integration-testing-annotations">
+ @TransactionConfiguration and
+
+ @Rollback annotations.See transaction management with the TestContext framework.
-
+ Support classes for integration testingThe Spring TestContext Framework provides several
@@ -403,18 +402,18 @@
-
+ JDBC Testing SupportThe org.springframework.test.jdbc package
contains SimpleJdbcTestUtils, which is a
collection of JDBC related utility functions intended to simplify
standard database testing scenarios. Note that
- AbstractTransactionalJUnit4SpringContextTests
- and
- AbstractTransactionalTestNGSpringContextTests
- provide convenience methods which delegate to
+ linkend="testcontext-support-classes-junit4">
+ AbstractTransactionalJUnit4SpringContextTests
+ and
+ AbstractTransactionalTestNGSpringContextTests
+ provide convenience methods which delegate to
SimpleJdbcTestUtils internally.The spring-jdbc module provides support for
@@ -424,10 +423,10 @@
linkend="jdbc-embedded-database-dao-testing" />.
-
+ Annotations
-
+ Spring Testing AnnotationsThe Spring Framework provides the following set of
@@ -439,11 +438,9 @@
-
-
- @ContextConfiguration
-
-
+
+ @ContextConfiguration
+ Defines class-level metadata that is used to determine how
to load and configure an
@@ -501,11 +498,8 @@ public class CustomLoaderXmlApplicationContextTests {
-
-
- @ActiveProfiles
-
-
+
+ @ActiveProfilesA class-level annotation that is used to declare which
bean definition profiles should be active
@@ -538,11 +532,8 @@ public class DeveloperIntegrationTests {
-
-
- @DirtiesContext
-
-
+
+ @DirtiesContextIndicates that the underlying Spring
ApplicationContext has been
@@ -610,11 +601,9 @@ public void testProcessWhichDirtiesAppCtx() {
-
-
- @TestExecutionListeners
-
-
+
+ @TestExecutionListeners
+ Defines class-level metadata for configuring which
TestExecutionListeners should be
@@ -635,17 +624,18 @@ public class CustomTestExecutionListenerTests {
-
-
- @TransactionConfiguration
-
-
+
+ @TransactionConfiguration
+ Defines class-level metadata for configuring transactional
tests. Specifically, the bean name of the
PlatformTransactionManager that is
- to be used to drive transactions can be explicitly configured if
- the bean name of the desired
+ to be used to drive transactions can be explicitly specified if
+ there are multiple beans of type
+ PlatformTransactionManager in the
+ test's ApplicationContext and the
+ bean name of the desired
PlatformTransactionManager is not
"transactionManager". In addition, you can change the
defaultRollback flag to
@@ -666,20 +656,17 @@ public class CustomConfiguredTransactionalTests {
If the default conventions are sufficient for your test
configuration, you can avoid using
@TransactionConfiguration
- altogether. In other words, if your transaction manager bean is
- named "transactionManager" and if you want transactions to roll
- back automatically, there is no need to annotate your test class
- with
+ altogether. In other words, if you have only one transaction
+ manger (or your transaction manager bean is named
+ "transactionManager") and if you want transactions to roll back
+ automatically, there is no need to annotate your test class with
@TransactionConfiguration.
-
-
- @Rollback
-
-
+
+ @RollbackIndicates whether the transaction for the annotated test
method should be rolled back after the test
@@ -696,11 +683,9 @@ public void testProcessWithoutRollback() {
-
-
- @BeforeTransaction
-
-
+
+ @BeforeTransaction
+ Indicates that the annotated public void
method should be executed before a
@@ -715,11 +700,9 @@ public void testProcessWithoutRollback() {
-
-
- @AfterTransaction
-
-
+
+ @AfterTransaction
+ Indicates that the annotated public void
method should be executed after a transaction
@@ -734,11 +717,9 @@ public void testProcessWithoutRollback() {
-
-
- @NotTransactional
-
-
+
+ @NotTransactional
+ The presence of this annotation indicates that the annotated
test method must not execute in a
@@ -771,7 +752,7 @@ public void testProcessWithoutTransaction() {
-
+ Standard Annotation SupportThe following annotations are supported with standard semantics
@@ -781,70 +762,54 @@ public void testProcessWithoutTransaction() {
-
-
- @Autowired
-
-
+
+ @Autowired
-
-
- @Qualifier
-
-
+
+ @Qualifier
- @Resource
- (javax.annotation) if JSR-250 is
+ @Resource
+ (javax.annotation) if JSR-250 is
present
- @Inject
- (javax.inject) if JSR-330 is
- present
+ @Inject (javax.inject)
+ if JSR-330 is present
-
- @Named
- (javax.inject) if JSR-330 is
+ @Named
+ (javax.inject) if JSR-330 is
present
- @PersistenceContext
- (javax.persistence) if JPA is
- present
+ @PersistenceContext
+ (javax.persistence) if JPA is present
- @PersistenceUnit
- (javax.persistence) if JPA is
- present
+ @PersistenceUnit
+ (javax.persistence) if JPA is present
-
-
- @Required
-
-
+
+ @Required
-
-
- @Transactional
-
-
+
+ @Transactional
@@ -875,7 +840,7 @@ public void testProcessWithoutTransaction() {
-
+ Spring JUnit Testing AnnotationsThe following annotations are only
@@ -886,11 +851,8 @@ public void testProcessWithoutTransaction() {
-
-
- @IfProfileValue
-
-
+
+ @IfProfileValueIndicates that the annotated test is enabled for a specific
testing environment. If the configured
@@ -925,11 +887,9 @@ public void testProcessWhichRunsForUnitOrIntegrationTestGroups() {
-
-
- @ProfileValueSourceConfiguration
-
-
+
+ @ProfileValueSourceConfiguration
+ Class-level annotation that specifies what type of
ProfileValueSource to use when retrieving
@@ -947,11 +907,8 @@ public class CustomProfileValueSourceTests {
-
-
- @Timed
-
-
+ @Timed
+ Indicates that the annotated test method must finish
execution in a specified time period (in milliseconds). If the
@@ -985,11 +942,8 @@ public void testProcessWithOneSecondTimeout() {
-
-
- @Repeat
-
-
+
+ @RepeatIndicates that the annotated test method must be executed
repeatedly. The number of times that the test method is to be
@@ -1009,7 +963,7 @@ public void testProcessRepeatedly() {
-
+ Spring TestContext FrameworkThe Spring TestContext
@@ -1041,7 +995,7 @@ public void testProcessRepeatedly() {
linkend="integration-testing-annotations">annotation support
sections.
-
+ Key abstractionsThe core of the framework consists of the
@@ -1202,7 +1156,7 @@ public void testProcessRepeatedly() {
with the framework.
-
+ Context managementEach TestContext provides context
@@ -1264,7 +1218,7 @@ public class MyTest {
@ContextConfiguration
annotation.
-
+ Context configuration with XML resourcesTo load an ApplicationContext
@@ -1323,14 +1277,14 @@ public class MyTest {
package com.example;
@RunWith(SpringJUnit4ClassRunner.class)
-// ApplicationContext will be loaded from "classpath:/com/example/MyTest-context.xml"
+// ApplicationContext will be loaded from "classpath:/com/example/MyTest-context.xml"@ContextConfiguration
public class MyTest {
// class body...
}
-
+ Context configuration with annotated classesTo load an ApplicationContext
@@ -1397,7 +1351,7 @@ public class OrderServiceTest {
}
-
+ Mixing XML resources and annotated classesIt may sometimes be desirable to mix XML resources and
@@ -1433,7 +1387,7 @@ public class OrderServiceTest {
other type of configuration.
-
+ Context configuration inheritance@ContextConfiguration supports
@@ -1466,13 +1420,13 @@ public class OrderServiceTest {
"base-config.xml".@RunWith(SpringJUnit4ClassRunner.class)
-// ApplicationContext will be loaded from "/base-config.xml" in the root of the classpath
+// ApplicationContext will be loaded from "/base-config.xml" in the root of the classpath@ContextConfiguration("/base-config.xml")
public class BaseTest {
// class body...
}
-// ApplicationContext will be loaded from "/base-config.xml" and "/extended-config.xml"
+// ApplicationContext will be loaded from "/base-config.xml" and "/extended-config.xml"// in the root of the classpath@ContextConfiguration("/extended-config.xml")
public class ExtendedTest extends BaseTest {
@@ -1502,7 +1456,7 @@ public class ExtendedTest extends BaseTest {
}
-
+ Context configuration with environment profilesSpring 3.1 introduces first-class support in the framework for
@@ -1711,7 +1665,7 @@ public class TransferServiceTest {
-
+ Context cachingOnce the TestContext framework loads an
@@ -1733,35 +1687,23 @@ public class TransferServiceTest {
-
- locations
-
- (from @ContextConfiguration)
-
+ locations(from
+ @ContextConfiguration)
-
- classes
-
- (from @ContextConfiguration)
-
+ classes(from
+ @ContextConfiguration)
-
- contextLoader
-
- (from @ContextConfiguration)
-
+ contextLoader(from
+ @ContextConfiguration)
-
- activeProfiles
-
- (from @ActiveProfiles)
-
+ activeProfiles(from
+ @ActiveProfiles)
@@ -1799,8 +1741,8 @@ public class TransferServiceTest {
executing tests with a build framework such as Ant, Maven, or
Gradle it is important to make sure that the build framework does
not fork between tests. For example, if the
- forkMode
+ forkMode
for the Maven Surefire plug-in is set to always
or pertest, the TestContext framework will not
be able to cache application contexts between test classes and the
@@ -1823,7 +1765,7 @@ public class TransferServiceTest {
-
+ Dependency injection of test fixturesWhen you use the
@@ -1848,13 +1790,13 @@ public class TransferServiceTest {
Because @Autowired is used to
- perform
- autowiring by type
- , if you have multiple bean definitions of the same type, you
- cannot rely on this approach for those particular beans. In that case,
- you can use @Autowired in conjunction
- with @Qualifier. As of Spring 3.0 you
- may also choose to use @Inject in
+ perform autowiring
+ by type , if you have multiple bean definitions of
+ the same type, you cannot rely on this approach for those particular
+ beans. In that case, you can use
+ @Autowired in conjunction with
+ @Qualifier. As of Spring 3.0 you may
+ also choose to use @Inject in
conjunction with @Named. Alternatively,
if your test class has access to its
ApplicationContext, you can perform an explicit
@@ -1901,8 +1843,7 @@ public class TransferServiceTest {
@ContextConfiguration("repository-config.xml")
public class HibernateTitleRepositoryTests {
- // this instance will be dependency injected by type
+ // this instance will be dependency injected by type@Autowired
private HibernateTitleRepository titleRepository;
@@ -1922,8 +1863,7 @@ public class HibernateTitleRepositoryTests {
@ContextConfiguration("repository-config.xml")
public class HibernateTitleRepositoryTests {
- // this instance will be dependency injected by type
+ // this instance will be dependency injected by type
private HibernateTitleRepository titleRepository;
@Autowired
@@ -1949,7 +1889,7 @@ public class HibernateTitleRepositoryTests {
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
- <!-- this bean will be injected into the HibernateTitleRepositoryTests class -->
+ <!-- this bean will be injected into the HibernateTitleRepositoryTests class -->
<bean id="titleRepository" class="com.foo.repository.hibernate.HibernateTitleRepository">
<property name="sessionFactory" ref="sessionFactory"/>
@@ -1994,7 +1934,7 @@ public class HibernateTitleRepositoryTests {
-
+ Transaction managementIn the TestContext framework, transactions are managed by the
@@ -2010,10 +1950,11 @@ public class HibernateTitleRepositoryTests {
@Transactional either at the class or
method level for your tests.
- For class-level transaction configuration (i.e., setting the
- bean name for the transaction manager and the default rollback flag),
- see the @TransactionConfiguration entry
- in the annotation
+ For class-level transaction configuration (i.e., setting an
+ explicit bean name for the transaction manager and the default
+ rollback flag), see the
+ @TransactionConfiguration entry in the
+ annotation
support section.If transactions are not enabled for the entire test class, you
@@ -2023,14 +1964,12 @@ public class HibernateTitleRepositoryTests {
the @Rollback annotation to override
the class-level default rollback setting.
-
-
- AbstractTransactionalJUnit4SpringContextTests
- and
- AbstractTransactionalTestNGSpringContextTests
- are preconfigured for transactional support at the class
- level.
-
+
+ AbstractTransactionalJUnit4SpringContextTests
+ and
+ AbstractTransactionalTestNGSpringContextTests
+ are preconfigured for transactional support at the class
+ level.Occasionally you need to execute certain code before or after a
transactional test method but outside the transactional context, for
@@ -2104,7 +2043,7 @@ public class FictitiousTransactionalTest {
}
-
+ Avoid false positives when testing ORM code
@@ -2144,10 +2083,10 @@ public void updateWithSessionFlush() {
-
+ TestContext support classes
-
+ JUnit support classesThe org.springframework.test.context.junit4
@@ -2227,7 +2166,7 @@ public void updateWithSessionFlush() {
-
+ Spring JUnit RunnerThe Spring TestContext Framework offers
@@ -2257,7 +2196,7 @@ public class SimpleTest {
}
-
+ TestNG support classesThe org.springframework.test.context.testng
@@ -2339,7 +2278,7 @@ public class SimpleTest {
-
+ PetClinic ExampleThe PetClinic application, available from the
-
+ Further ResourcesConsult the following resources for more information about
@@ -2484,62 +2423,61 @@ public class HibernateClinicTests extends AbstractClinicTests { }
- JUnit:
- A programmer-oriented testing framework for
- Java
- . Used by the Spring Framework in its test suite.
+ JUnit:
+ A programmer-oriented testing framework for Java
+ . Used by the Spring Framework in its test suite.
- TestNG: A testing
+ TestNG: A testing
framework inspired by JUnit with added support for Java 5 annotations,
test groups, data-driven testing, distributed testing, etc.
- MockObjects.com: Web site
- dedicated to mock objects, a technique for improving the design of
- code within test-driven development.
+ MockObjects.com: Web
+ site dedicated to mock objects, a technique for improving the design
+ of code within test-driven development.
- "Mock
- Objects": Article in Wikipedia.
+ "Mock
+ Objects": Article in Wikipedia.
- EasyMock: Java
- library
- that provides Mock Objects for interfaces (and objects
- through the class extension) by generating them on the fly using
- Java's proxy mechanism.
- Used by the Spring Framework in its test suite.
+ EasyMock:
+ Java library that provides Mock Objects for
+ interfaces (and objects through the class extension) by generating
+ them on the fly using Java's proxy mechanism. Used
+ by the Spring Framework in its test suite.
- JMock: Library that
- supports test-driven development of Java code with mock
+ JMock: Library
+ that supports test-driven development of Java code with mock
objects.
- Mockito: Java mock
- library based on the test spy
+ Mockito: Java mock
+ library based on the test spy
pattern.
- DbUnit:
+ DbUnit:
JUnit extension (also usable with Ant and Maven) targeted for
database-driven projects that, among other things, puts your database
into a known state between test runs.
- The
- Grinder: Java load testing framework.
+ The
+ Grinder: Java load testing framework.