From f21fe33e74ac3844a5690f71266e07c78ec219dd Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Sat, 28 Jul 2012 00:06:46 +0200 Subject: [PATCH] Support single, unqualified tx manager in the TCF TransactionalTestExecutionListener currently requires that the PlatformTransactionManager bean be named "transactionManager" by default. Otherwise, the bean name can only be overridden via the transactionManager attribute of @TransactionConfiguration or the value attribute of @Transactional. However, if there is only a single PlatformTransactionManager in the test's ApplicationContext, then the requirement to specify the exact name of that bean (or to name it exactly "transactionManager") is often superfluous. This commit addresses this issue by refactoring the TransactionalTestExecutionListener so that it is comparable to the algorithm for determining the transaction manager used in TransactionAspectSupport for "production" code. Specifically, the TTEL now uses the following algorithm to retrieve the transaction manager. - look up by type and qualifier from @Transactional - else, look up by type and explicit name from @TransactionConfiguration - else, look up single bean by type - else, look up by type and default name from @TransactionConfiguration Issue: SPR-9645 --- .../transaction/TransactionConfiguration.java | 31 +- .../TransactionalTestExecutionListener.java | 214 +++++---- .../spr9645/LookUpNonexistentTxMgrTests.java | 77 ++++ .../LookUpTxMgrByTypeAndDefaultNameTests.java | 84 ++++ .../LookUpTxMgrByTypeAndNameTests.java | 86 ++++ ...grByTypeAndQualifierAtClassLevelTests.java | 84 ++++ ...rByTypeAndQualifierAtMethodLevelTests.java | 84 ++++ .../spr9645/LookUpTxMgrByTypeTests.java | 77 ++++ .../CallCountingTransactionManager.java | 61 +++ spring-test/src/test/resources/log4j.xml | 4 + src/dist/changelog.txt | 1 + src/reference/docbook/testing.xml | 408 ++++++++---------- 12 files changed, 879 insertions(+), 332 deletions(-) create mode 100644 spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpNonexistentTxMgrTests.java create mode 100644 spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndDefaultNameTests.java create mode 100644 spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndNameTests.java create mode 100644 spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndQualifierAtClassLevelTests.java create mode 100644 spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeAndQualifierAtMethodLevelTests.java create mode 100644 spring-test/src/test/java/org/springframework/test/context/junit4/spr9645/LookUpTxMgrByTypeTests.java create mode 100644 spring-test/src/test/java/org/springframework/test/transaction/CallCountingTransactionManager.java 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 c2c72c7c34..e62317b783 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 2e533ad463..e182259ba7 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 0000000000..0a70b0d0a2 --- /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 0000000000..5cfdebaba3 --- /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 0000000000..805243f11c --- /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 0000000000..cd78baea45 --- /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 0000000000..0a9335dbca --- /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 0000000000..ed48479805 --- /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 0000000000..8713dbe5ee --- /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 bcfcb8f81a..873d2ccdc4 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 d5406a535f..4c8f1c6443 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 1af3b663f4..0f8a4bf064 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 Testing Testing is an integral part of enterprise software development. This @@ -20,7 +20,7 @@ this reference manual.)
-
+
Unit Testing Dependency 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 -
+
JNDI The org.springframework.mock.jndi package @@ -59,20 +59,20 @@ testing scenarios without modification.
-
+
Servlet API The 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 API The org.springframework.mock.web.portlet @@ -81,10 +81,10 @@
-
+
Unit Testing support Classes -
+
General utilities The org.springframework.test.util package @@ -115,7 +115,7 @@
-
+
Spring MVC The 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 -
+
Overview It is important to be able to perform some integration testing @@ -211,7 +211,7 @@
-
+
Goals of Integration Testing Spring'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 caching The Spring TestContext Framework provides consistent loading of @@ -284,7 +284,7 @@ framework.
-
+
Dependency Injection of test fixtures When the TestContext framework loads your application context, @@ -328,7 +328,7 @@ linkend="testcontext-fixture-di">TestContext framework.
-
+
Transaction management One 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 testing The Spring TestContext Framework provides several @@ -403,18 +402,18 @@
-
+
JDBC Testing Support The 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 Annotations The 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 - - + + @ActiveProfiles A class-level annotation that is used to declare which bean definition profiles should be active @@ -538,11 +532,8 @@ public class DeveloperIntegrationTests { - - - @DirtiesContext - - + + @DirtiesContext Indicates 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 - - + + @Rollback Indicates 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 Support The 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 Annotations The following annotations are only @@ -886,11 +851,8 @@ public void testProcessWithoutTransaction() { - - - @IfProfileValue - - + + @IfProfileValue Indicates 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 - - + + @Repeat Indicates 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 Framework The Spring TestContext @@ -1041,7 +995,7 @@ public void testProcessRepeatedly() { linkend="integration-testing-annotations">annotation support sections. -
+
Key abstractions The core of the framework consists of the @@ -1202,7 +1156,7 @@ public void testProcessRepeatedly() { with the framework.
-
+
Context management Each TestContext provides context @@ -1264,7 +1218,7 @@ public class MyTest { @ContextConfiguration annotation. -
+
Context configuration with XML resources To 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 classes To load an ApplicationContext @@ -1397,7 +1351,7 @@ public class OrderServiceTest { }
-
+
Mixing XML resources and annotated classes It 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 profiles Spring 3.1 introduces first-class support in the framework for @@ -1711,7 +1665,7 @@ public class TransferServiceTest {
-
+
Context caching Once 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 fixtures When 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 management In 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 classes The org.springframework.test.context.junit4 @@ -2227,7 +2166,7 @@ public void updateWithSessionFlush() {
-
+
Spring JUnit Runner The Spring TestContext Framework offers @@ -2257,7 +2196,7 @@ public class SimpleTest { }
-
+
TestNG support classes The org.springframework.test.context.testng @@ -2339,7 +2278,7 @@ public class SimpleTest {
-
+
PetClinic Example The PetClinic application, available from the
-
+
Further Resources Consult 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.
-- GitLab