Provide meta-annotation support in the TCF

Spring 3.0 already allows component stereotypes to be used in a
meta-annotation fashion, for example by creating a custom
@TransactionalService stereotype annotation which combines
@Transactional and @Service in a single, reusable, application-specific
annotation. However, the Spring TestContext Framework (TCF) currently
does not provide any support for test-related annotations to be used as
meta-annotations.

This commit overhauls the TCF with regard to how annotations are
retrieved and adds explicit support for the following annotations to be
used as meta-annotations in conjunction with the TCF.

- @ContextConfiguration
- @ContextHierarchy
- @ActiveProfiles
- @DirtiesContext
- @IfProfileValue
- @ProfileValueSourceConfiguration
- @BeforeTransaction
- @AfterTransaction
- @TransactionConfiguration
- @Rollback
- @TestExecutionListeners
- @Repeat
- @Timed
- @WebAppConfiguration

Note that meta-annotation support for @Transactional was already
available prior to this commit.

The following is a summary of the major changes included in this commit.

- Now using AnnotationUtils.getAnnotation() instead of
  Class.getAnnotation() where appropriate in the TestContext Framework.
- Now using AnnotationUtils.findAnnotation() instead of
  Class.isAnnotationPresent() where appropriate in the TestContext
  Framework.
- Introduced findAnnotationPrefersInteracesOverLocalMetaAnnotations() in
  AnnotationUtilsTests in order to verify the status quo.
- AnnotationUtils.findAnnotationDeclaringClass() and
  AnnotationUtils.findAnnotationDeclaringClassForTypes() now support
  meta annotations.
- Introduced MetaAnnotationUtils and AnnotationDescriptor in the
  spring-test module.
- Introduced UntypedAnnotationDescriptor in MetaAnnotationUtils.
- Introduced findAnnotationDescriptorForTypes() in MetaAnnotationUtils.
- ContextLoaderUtils now uses MetaAnnotationUtils for looking up
  @ActiveProfiles as a potential meta-annotation.
- TestContextManager now uses MetaAnnotationUtils for looking up
  @TestExecutionListeners as a potential meta-annotation.
- DirtiesContextTestExecutionListener now uses AnnotationUtils for
  looking up @DirtiesContext as a potential meta-annotation.
- Introduced DirtiesContextTestExecutionListenerTests.
- ProfileValueUtils now uses AnnotationUtils for looking up
  @IfProfileValue and @ProfileValueSourceConfiguration as potential
  meta-annotations.
- @BeforeTransaction and @AfterTransaction now support ANNOTATION_TYPE
  as a target, allowing them to be used as meta-annotations.
- TransactionalTestExecutionListener now uses AnnotationUtils for
  looking up @BeforeTransaction, @AfterTransaction, @Rollback, and
  @TransactionConfiguration as potential meta-annotations.
- Introduced TransactionalTestExecutionListenerTests.
- @Repeat and @Timed now support ANNOTATION_TYPE as a target, allowing
  them to be used as meta-annotations.
- SpringJUnit4ClassRunner now uses AnnotationUtils for looking up
  @Repeat and @Timed as potential meta-annotations.
- Moved all remaining logic for building the MergedContextConfiguration
  from the DefaultTestContext constructor to
  ContextLoaderUtils.buildMergedContextConfiguration().
- Verified meta-annotation support for @WebAppConfiguration and
  @ContextConfiguration.

Issue: SPR-7827
This commit is contained in:
Sam Brannen
2013-07-01 23:01:31 -04:00
parent 56dfcd153e
commit 5e7021f3f7
28 changed files with 1852 additions and 205 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -16,14 +16,15 @@
package org.springframework.test.annotation;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Unit tests for {@link ProfileValueUtils}.
*
@@ -88,8 +89,12 @@ public class ProfileValueUtilsTests {
assertClassIsEnabled(NonAnnotated.class);
assertClassIsEnabled(EnabledAnnotatedSingleValue.class);
assertClassIsEnabled(EnabledAnnotatedMultiValue.class);
assertClassIsEnabled(MetaEnabledClass.class);
assertClassIsEnabled(MetaEnabledWithCustomProfileValueSourceClass.class);
assertClassIsDisabled(DisabledAnnotatedSingleValue.class);
assertClassIsDisabled(DisabledAnnotatedMultiValue.class);
assertClassIsDisabled(MetaDisabledClass.class);
assertClassIsDisabled(MetaDisabledWithCustomProfileValueSourceClass.class);
}
@Test
@@ -100,6 +105,10 @@ public class ProfileValueUtilsTests {
assertMethodIsEnabled(ENABLED_ANNOTATED_METHOD, EnabledAnnotatedSingleValue.class);
assertMethodIsDisabled(DISABLED_ANNOTATED_METHOD, EnabledAnnotatedSingleValue.class);
assertMethodIsEnabled(NON_ANNOTATED_METHOD, MetaEnabledAnnotatedSingleValue.class);
assertMethodIsEnabled(ENABLED_ANNOTATED_METHOD, MetaEnabledAnnotatedSingleValue.class);
assertMethodIsDisabled(DISABLED_ANNOTATED_METHOD, MetaEnabledAnnotatedSingleValue.class);
assertMethodIsEnabled(NON_ANNOTATED_METHOD, EnabledAnnotatedMultiValue.class);
assertMethodIsEnabled(ENABLED_ANNOTATED_METHOD, EnabledAnnotatedMultiValue.class);
assertMethodIsDisabled(DISABLED_ANNOTATED_METHOD, EnabledAnnotatedMultiValue.class);
@@ -108,6 +117,10 @@ public class ProfileValueUtilsTests {
assertMethodIsDisabled(ENABLED_ANNOTATED_METHOD, DisabledAnnotatedSingleValue.class);
assertMethodIsDisabled(DISABLED_ANNOTATED_METHOD, DisabledAnnotatedSingleValue.class);
assertMethodIsDisabled(NON_ANNOTATED_METHOD, MetaDisabledAnnotatedSingleValue.class);
assertMethodIsDisabled(ENABLED_ANNOTATED_METHOD, MetaDisabledAnnotatedSingleValue.class);
assertMethodIsDisabled(DISABLED_ANNOTATED_METHOD, MetaDisabledAnnotatedSingleValue.class);
assertMethodIsDisabled(NON_ANNOTATED_METHOD, DisabledAnnotatedMultiValue.class);
assertMethodIsDisabled(ENABLED_ANNOTATED_METHOD, DisabledAnnotatedMultiValue.class);
assertMethodIsDisabled(DISABLED_ANNOTATED_METHOD, DisabledAnnotatedMultiValue.class);
@@ -211,4 +224,82 @@ public class ProfileValueUtilsTests {
}
}
@IfProfileValue(name = NAME, value = VALUE)
@Retention(RetentionPolicy.RUNTIME)
private static @interface MetaEnabled {
}
@IfProfileValue(name = NAME, value = VALUE + "X")
@Retention(RetentionPolicy.RUNTIME)
private static @interface MetaDisabled {
}
@MetaEnabled
private static class MetaEnabledClass {
}
@MetaDisabled
private static class MetaDisabledClass {
}
@SuppressWarnings("unused")
@MetaEnabled
private static class MetaEnabledAnnotatedSingleValue {
public void nonAnnotatedMethod() {
}
@MetaEnabled
public void enabledAnnotatedMethod() {
}
@MetaDisabled
public void disabledAnnotatedMethod() {
}
}
@SuppressWarnings("unused")
@MetaDisabled
private static class MetaDisabledAnnotatedSingleValue {
public void nonAnnotatedMethod() {
}
@MetaEnabled
public void enabledAnnotatedMethod() {
}
@MetaDisabled
public void disabledAnnotatedMethod() {
}
}
public static class HardCodedProfileValueSource implements ProfileValueSource {
@Override
public String get(final String key) {
return (key.equals(NAME) ? "42" : null);
}
}
@ProfileValueSourceConfiguration(HardCodedProfileValueSource.class)
@IfProfileValue(name = NAME, value = "42")
@Retention(RetentionPolicy.RUNTIME)
private static @interface MetaEnabledWithCustomProfileValueSource {
}
@ProfileValueSourceConfiguration(HardCodedProfileValueSource.class)
@IfProfileValue(name = NAME, value = "13")
@Retention(RetentionPolicy.RUNTIME)
private static @interface MetaDisabledWithCustomProfileValueSource {
}
@MetaEnabledWithCustomProfileValueSource
private static class MetaEnabledWithCustomProfileValueSourceClass {
}
@MetaDisabledWithCustomProfileValueSource
private static class MetaDisabledWithCustomProfileValueSourceClass {
}
}

View File

@@ -16,6 +16,10 @@
package org.springframework.test.context;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Collections;
import java.util.Set;
@@ -40,6 +44,16 @@ abstract class AbstractContextLoaderUtilsTests {
Collections.<Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>> emptySet();
void assertAttributes(ContextConfigurationAttributes attributes, Class<?> expectedDeclaringClass,
String[] expectedLocations, Class<?>[] expectedClasses,
Class<? extends ContextLoader> expectedContextLoaderClass, boolean expectedInheritLocations) {
assertEquals(expectedDeclaringClass, attributes.getDeclaringClass());
assertArrayEquals(expectedLocations, attributes.getLocations());
assertArrayEquals(expectedClasses, attributes.getClasses());
assertEquals(expectedInheritLocations, attributes.isInheritLocations());
assertEquals(expectedContextLoaderClass, attributes.getContextLoaderClass());
}
void assertMergedConfig(MergedContextConfiguration mergedConfig, Class<?> expectedTestClass,
String[] expectedLocations, Class<?>[] expectedClasses,
Class<? extends ContextLoader> expectedContextLoaderClass) {
@@ -61,7 +75,13 @@ abstract class AbstractContextLoaderUtilsTests {
assertNotNull(mergedConfig.getClasses());
assertArrayEquals(expectedClasses, mergedConfig.getClasses());
assertNotNull(mergedConfig.getActiveProfiles());
assertEquals(expectedContextLoaderClass, mergedConfig.getContextLoader().getClass());
System.err.println(expectedContextLoaderClass);
if (expectedContextLoaderClass == null) {
assertNull(mergedConfig.getContextLoader());
}
else {
assertEquals(expectedContextLoaderClass, mergedConfig.getContextLoader().getClass());
}
assertNotNull(mergedConfig.getContextInitializerClasses());
assertEquals(expectedInitializerClasses, mergedConfig.getContextInitializerClasses());
}
@@ -83,6 +103,28 @@ abstract class AbstractContextLoaderUtilsTests {
static class BarConfig {
}
@ContextConfiguration("/foo.xml")
@ActiveProfiles(profiles = "foo")
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public static @interface MetaLocationsFooConfig {
}
@ContextConfiguration("/bar.xml")
@ActiveProfiles(profiles = "bar")
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public static @interface MetaLocationsBarConfig {
}
@MetaLocationsFooConfig
static class MetaLocationsFoo {
}
@MetaLocationsBarConfig
static class MetaLocationsBar extends MetaLocationsFoo {
}
@ContextConfiguration(locations = "/foo.xml", inheritLocations = false)
@ActiveProfiles(profiles = "foo")
static class LocationsFoo {

View File

@@ -16,6 +16,10 @@
package org.springframework.test.context;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Arrays;
import java.util.List;
@@ -107,6 +111,44 @@ public class ContextLoaderUtilsActiveProfilesTests extends AbstractContextLoader
assertTrue(list.contains("cat"));
}
/**
* @since 4.0
*/
@Test
public void resolveActiveProfilesWithMetaAnnotation() {
String[] profiles = resolveActiveProfiles(MetaLocationsFoo.class);
assertNotNull(profiles);
assertArrayEquals(new String[] { "foo" }, profiles);
}
/**
* @since 4.0
*/
@Test
public void resolveActiveProfilesWithLocalAndInheritedMetaAnnotations() {
String[] profiles = resolveActiveProfiles(MetaLocationsBar.class);
assertNotNull(profiles);
assertEquals(2, profiles.length);
List<String> list = Arrays.asList(profiles);
assertTrue(list.contains("foo"));
assertTrue(list.contains("bar"));
}
/**
* @since 4.0
*/
@Test
public void resolveActiveProfilesWithOverriddenMetaAnnotation() {
String[] profiles = resolveActiveProfiles(MetaAnimals.class);
assertNotNull(profiles);
assertEquals(2, profiles.length);
List<String> list = Arrays.asList(profiles);
assertTrue(list.contains("dog"));
assertTrue(list.contains("cat"));
}
/**
* @since 4.0
*/
@@ -208,6 +250,16 @@ public class ContextLoaderUtilsActiveProfilesTests extends AbstractContextLoader
private static class Animals extends LocationsBar {
}
@ActiveProfiles(profiles = { "dog", "cat" }, inheritProfiles = false)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
private static @interface MetaAnimalsConfig {
}
@MetaAnimalsConfig
private static class MetaAnimals extends MetaLocationsBar {
}
private static class InheritedLocationsFoo extends LocationsFoo {
}

View File

@@ -32,16 +32,6 @@ import static org.springframework.test.context.ContextLoaderUtils.*;
*/
public class ContextLoaderUtilsConfigurationAttributesTests extends AbstractContextLoaderUtilsTests {
private void assertAttributes(ContextConfigurationAttributes attributes, Class<?> expectedDeclaringClass,
String[] expectedLocations, Class<?>[] expectedClasses,
Class<? extends ContextLoader> expectedContextLoaderClass, boolean expectedInheritLocations) {
assertEquals(expectedDeclaringClass, attributes.getDeclaringClass());
assertArrayEquals(expectedLocations, attributes.getLocations());
assertArrayEquals(expectedClasses, attributes.getClasses());
assertEquals(expectedInheritLocations, attributes.isInheritLocations());
assertEquals(expectedContextLoaderClass, attributes.getContextLoaderClass());
}
private void assertLocationsFooAttributes(ContextConfigurationAttributes attributes) {
assertAttributes(attributes, LocationsFoo.class, new String[] { "/foo.xml" }, EMPTY_CLASS_ARRAY,
ContextLoader.class, false);
@@ -84,6 +74,26 @@ public class ContextLoaderUtilsConfigurationAttributesTests extends AbstractCont
assertLocationsFooAttributes(attributesList.get(0));
}
@Test
public void resolveConfigAttributesWithMetaAnnotationAndLocations() {
List<ContextConfigurationAttributes> attributesList = resolveContextConfigurationAttributes(MetaLocationsFoo.class);
assertNotNull(attributesList);
assertEquals(1, attributesList.size());
assertAttributes(attributesList.get(0), MetaLocationsFooConfig.class, new String[] { "/foo.xml" },
EMPTY_CLASS_ARRAY, ContextLoader.class, true);
}
@Test
public void resolveConfigAttributesWithMetaAnnotationAndLocationsInClassHierarchy() {
List<ContextConfigurationAttributes> attributesList = resolveContextConfigurationAttributes(MetaLocationsBar.class);
assertNotNull(attributesList);
assertEquals(2, attributesList.size());
assertAttributes(attributesList.get(0), MetaLocationsBarConfig.class, new String[] { "/bar.xml" },
EMPTY_CLASS_ARRAY, ContextLoader.class, true);
assertAttributes(attributesList.get(1), MetaLocationsFooConfig.class, new String[] { "/foo.xml" },
EMPTY_CLASS_ARRAY, ContextLoader.class, true);
}
@Test
public void resolveConfigAttributesWithLocalAnnotationAndClasses() {
List<ContextConfigurationAttributes> attributesList = resolveContextConfigurationAttributes(ClassesFoo.class);

View File

@@ -16,6 +16,8 @@
package org.springframework.test.context;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -33,7 +35,7 @@ import static org.springframework.test.context.ContextLoaderUtils.*;
* Unit tests for {@link ContextLoaderUtils} involving context hierarchies.
*
* @author Sam Brannen
* @since 3.1
* @since 3.2.2
*/
public class ContextLoaderUtilsContextHierarchyTests extends AbstractContextLoaderUtilsTests {
@@ -48,6 +50,11 @@ public class ContextLoaderUtilsContextHierarchyTests extends AbstractContextLoad
resolveContextHierarchyAttributes(SingleTestClassWithContextConfigurationAndContextHierarchy.class);
}
@Test(expected = IllegalStateException.class)
public void resolveContextHierarchyAttributesForSingleTestClassWithContextConfigurationAndContextHierarchyOnSingleMetaAnnotation() {
resolveContextHierarchyAttributes(SingleTestClassWithContextConfigurationAndContextHierarchyOnSingleMetaAnnotation.class);
}
@Test
public void resolveContextHierarchyAttributesForSingleTestClassWithImplicitSingleLevelContextHierarchy() {
List<List<ContextConfigurationAttributes>> hierarchyAttributes = resolveContextHierarchyAttributes(BareAnnotations.class);
@@ -67,12 +74,34 @@ public class ContextLoaderUtilsContextHierarchyTests extends AbstractContextLoad
}
@Test
public void resolveContextHierarchyAttributesForSingleTestClassWithTripleLevelContextHierarchy() {
List<List<ContextConfigurationAttributes>> hierarchyAttributes = resolveContextHierarchyAttributes(SingleTestClassWithTripleLevelContextHierarchy.class);
public void resolveContextHierarchyAttributesForSingleTestClassWithSingleLevelContextHierarchyFromMetaAnnotation() {
List<List<ContextConfigurationAttributes>> hierarchyAttributes = resolveContextHierarchyAttributes(SingleTestClassWithSingleLevelContextHierarchyFromMetaAnnotation.class);
assertEquals(1, hierarchyAttributes.size());
List<ContextConfigurationAttributes> configAttributesList = hierarchyAttributes.get(0);
assertNotNull(configAttributesList);
assertEquals(1, configAttributesList.size());
debugConfigAttributes(configAttributesList);
assertAttributes(configAttributesList.get(0), ContextHierarchyA.class, new String[] { "A.xml" },
EMPTY_CLASS_ARRAY, ContextLoader.class, true);
}
@Test
public void resolveContextHierarchyAttributesForSingleTestClassWithTripleLevelContextHierarchy() {
Class<SingleTestClassWithTripleLevelContextHierarchy> testClass = SingleTestClassWithTripleLevelContextHierarchy.class;
List<List<ContextConfigurationAttributes>> hierarchyAttributes = resolveContextHierarchyAttributes(testClass);
assertEquals(1, hierarchyAttributes.size());
List<ContextConfigurationAttributes> configAttributesList = hierarchyAttributes.get(0);
assertNotNull(configAttributesList);
assertEquals(3, configAttributesList.size());
debugConfigAttributes(configAttributesList);
assertAttributes(configAttributesList.get(0), testClass, new String[] { "A.xml" }, EMPTY_CLASS_ARRAY,
ContextLoader.class, true);
assertAttributes(configAttributesList.get(1), testClass, new String[] { "B.xml" },
EMPTY_CLASS_ARRAY, ContextLoader.class, true);
assertAttributes(configAttributesList.get(2), testClass, new String[] { "C.xml" }, EMPTY_CLASS_ARRAY,
ContextLoader.class, true);
}
@Test
@@ -97,6 +126,34 @@ public class ContextLoaderUtilsContextHierarchyTests extends AbstractContextLoad
assertThat(configAttributesListClassLevel3.get(0).getLocations()[0], equalTo("three.xml"));
}
@Test
public void resolveContextHierarchyAttributesForTestClassHierarchyWithSingleLevelContextHierarchiesAndMetaAnnotations() {
List<List<ContextConfigurationAttributes>> hierarchyAttributes = resolveContextHierarchyAttributes(TestClass3WithSingleLevelContextHierarchyFromMetaAnnotation.class);
assertEquals(3, hierarchyAttributes.size());
List<ContextConfigurationAttributes> configAttributesListClassLevel1 = hierarchyAttributes.get(0);
debugConfigAttributes(configAttributesListClassLevel1);
assertEquals(1, configAttributesListClassLevel1.size());
assertThat(configAttributesListClassLevel1.get(0).getLocations()[0], equalTo("A.xml"));
assertAttributes(configAttributesListClassLevel1.get(0), ContextHierarchyA.class, new String[] { "A.xml" },
EMPTY_CLASS_ARRAY, ContextLoader.class, true);
List<ContextConfigurationAttributes> configAttributesListClassLevel2 = hierarchyAttributes.get(1);
debugConfigAttributes(configAttributesListClassLevel2);
assertEquals(1, configAttributesListClassLevel2.size());
assertArrayEquals(new String[] { "B-one.xml", "B-two.xml" },
configAttributesListClassLevel2.get(0).getLocations());
assertAttributes(configAttributesListClassLevel2.get(0), ContextHierarchyB.class, new String[] { "B-one.xml",
"B-two.xml" }, EMPTY_CLASS_ARRAY, ContextLoader.class, true);
List<ContextConfigurationAttributes> configAttributesListClassLevel3 = hierarchyAttributes.get(2);
debugConfigAttributes(configAttributesListClassLevel3);
assertEquals(1, configAttributesListClassLevel3.size());
assertThat(configAttributesListClassLevel3.get(0).getLocations()[0], equalTo("C.xml"));
assertAttributes(configAttributesListClassLevel3.get(0), ContextHierarchyC.class, new String[] { "C.xml" },
EMPTY_CLASS_ARRAY, ContextLoader.class, true);
}
@Test
public void resolveContextHierarchyAttributesForTestClassHierarchyWithBareContextConfigurationInSubclass() {
List<List<ContextConfigurationAttributes>> hierarchyAttributes = resolveContextHierarchyAttributes(TestClass2WithBareContextConfigurationInSubclass.class);
@@ -301,6 +358,16 @@ public class ContextLoaderUtilsContextHierarchyTests extends AbstractContextLoad
private static class SingleTestClassWithContextConfigurationAndContextHierarchy {
}
@ContextConfiguration("foo.xml")
@ContextHierarchy(@ContextConfiguration("bar.xml"))
@Retention(RetentionPolicy.RUNTIME)
private static @interface ContextConfigurationAndContextHierarchyOnSingleMeta {
}
@ContextConfigurationAndContextHierarchyOnSingleMeta
private static class SingleTestClassWithContextConfigurationAndContextHierarchyOnSingleMetaAnnotation {
}
@ContextHierarchy(@ContextConfiguration("A.xml"))
private static class SingleTestClassWithSingleLevelContextHierarchy {
}
@@ -465,7 +532,41 @@ public class ContextLoaderUtilsContextHierarchyTests extends AbstractContextLoad
public void initialize(ConfigurableApplicationContext applicationContext) {
/* no-op */
}
}
// -------------------------------------------------------------------------
@ContextHierarchy(@ContextConfiguration("A.xml"))
@Retention(RetentionPolicy.RUNTIME)
private static @interface ContextHierarchyA {
}
@ContextHierarchy(@ContextConfiguration({ "B-one.xml", "B-two.xml" }))
@Retention(RetentionPolicy.RUNTIME)
private static @interface ContextHierarchyB {
}
@ContextHierarchy(@ContextConfiguration("C.xml"))
@Retention(RetentionPolicy.RUNTIME)
private static @interface ContextHierarchyC {
}
@ContextHierarchyA
private static class SingleTestClassWithSingleLevelContextHierarchyFromMetaAnnotation {
}
@ContextHierarchyA
private static class TestClass1WithSingleLevelContextHierarchyFromMetaAnnotation {
}
@ContextHierarchyB
private static class TestClass2WithSingleLevelContextHierarchyFromMetaAnnotation extends
TestClass1WithSingleLevelContextHierarchyFromMetaAnnotation {
}
@ContextHierarchyC
private static class TestClass3WithSingleLevelContextHierarchyFromMetaAnnotation extends
TestClass2WithSingleLevelContextHierarchyFromMetaAnnotation {
}
}

View File

@@ -31,9 +31,12 @@ import static org.springframework.test.context.ContextLoaderUtils.*;
*/
public class ContextLoaderUtilsMergedConfigTests extends AbstractContextLoaderUtilsTests {
@Test(expected = IllegalArgumentException.class)
@Test
public void buildMergedConfigWithoutAnnotation() {
buildMergedContextConfiguration(Enigma.class, null, null);
Class<Enigma> testClass = Enigma.class;
MergedContextConfiguration mergedConfig = buildMergedContextConfiguration(testClass, null, null);
assertMergedConfig(mergedConfig, testClass, EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, null);
}
@Test
@@ -57,6 +60,15 @@ public class ContextLoaderUtilsMergedConfigTests extends AbstractContextLoaderUt
DelegatingSmartContextLoader.class);
}
@Test
public void buildMergedConfigWithMetaAnnotationAndLocations() {
Class<?> testClass = MetaLocationsFoo.class;
MergedContextConfiguration mergedConfig = buildMergedContextConfiguration(testClass, null, null);
assertMergedConfig(mergedConfig, testClass, new String[] { "classpath:/foo.xml" }, EMPTY_CLASS_ARRAY,
DelegatingSmartContextLoader.class);
}
@Test
public void buildMergedConfigWithLocalAnnotationAndClasses() {
Class<?> testClass = ClassesFoo.class;

View File

@@ -0,0 +1,321 @@
/*
* Copyright 2002-2013 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;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import org.junit.Test;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.test.context.MetaAnnotationUtils.AnnotationDescriptor;
import org.springframework.test.context.MetaAnnotationUtils.UntypedAnnotationDescriptor;
import org.springframework.transaction.annotation.Transactional;
import static org.junit.Assert.*;
import static org.springframework.test.context.MetaAnnotationUtils.*;
/**
* Unit tests for {@link MetaAnnotationUtils}.
*
* @author Sam Brannen
* @since 4.0
*/
public class MetaAnnotationUtilsTests {
private void assertComponentOnStereotype(Class<?> startClass, Class<?> declaringClass, String name,
Class<? extends Annotation> stereotypeType) {
AnnotationDescriptor<Component> descriptor = findAnnotationDescriptor(startClass, Component.class);
assertNotNull(descriptor);
assertEquals(declaringClass, descriptor.getDeclaringClass());
assertEquals(Component.class, descriptor.getAnnotationType());
assertEquals(name, descriptor.getAnnotation().value());
assertNotNull(descriptor.getStereotype());
assertEquals(stereotypeType, descriptor.getStereotypeType());
}
@SuppressWarnings("unchecked")
private void assertComponentOnStereotypeForMultipleCandidateTypes(Class<?> startClass, Class<?> declaringClass,
String name, Class<? extends Annotation> stereotypeType) {
Class<Component> annotationType = Component.class;
UntypedAnnotationDescriptor descriptor = findAnnotationDescriptorForTypes(startClass, Service.class,
annotationType, Order.class, Transactional.class);
assertNotNull(descriptor);
assertEquals(declaringClass, descriptor.getDeclaringClass());
assertEquals(annotationType, descriptor.getAnnotationType());
assertEquals(name, ((Component) descriptor.getAnnotation()).value());
assertNotNull(descriptor.getStereotype());
assertEquals(stereotypeType, descriptor.getStereotypeType());
}
@Test
public void findAnnotationDescriptorWithNoAnnotationPresent() throws Exception {
assertNull(findAnnotationDescriptor(NonAnnotatedInterface.class, Transactional.class));
assertNull(findAnnotationDescriptor(NonAnnotatedClass.class, Transactional.class));
}
@Test
public void findAnnotationDescriptorWithInheritedAnnotationOnClass() throws Exception {
// Note: @Transactional is inherited
assertEquals(InheritedAnnotationClass.class,
findAnnotationDescriptor(InheritedAnnotationClass.class, Transactional.class).getDeclaringClass());
assertEquals(InheritedAnnotationClass.class,
findAnnotationDescriptor(SubInheritedAnnotationClass.class, Transactional.class).getDeclaringClass());
}
@Test
public void findAnnotationDescriptorWithInheritedAnnotationOnInterface() throws Exception {
// Note: @Transactional is inherited
assertEquals(InheritedAnnotationInterface.class,
findAnnotationDescriptor(InheritedAnnotationInterface.class, Transactional.class).getDeclaringClass());
assertNull(findAnnotationDescriptor(SubInheritedAnnotationInterface.class, Transactional.class));
assertNull(findAnnotationDescriptor(SubSubInheritedAnnotationInterface.class, Transactional.class));
}
@Test
public void findAnnotationDescriptorForNonInheritedAnnotationOnClass() throws Exception {
// Note: @Order is not inherited.
assertEquals(NonInheritedAnnotationClass.class,
findAnnotationDescriptor(NonInheritedAnnotationClass.class, Order.class).getDeclaringClass());
assertEquals(NonInheritedAnnotationClass.class,
findAnnotationDescriptor(SubNonInheritedAnnotationClass.class, Order.class).getDeclaringClass());
}
@Test
public void findAnnotationDescriptorForNonInheritedAnnotationOnInterface() throws Exception {
// Note: @Order is not inherited.
assertEquals(NonInheritedAnnotationInterface.class,
findAnnotationDescriptor(NonInheritedAnnotationInterface.class, Order.class).getDeclaringClass());
assertNull(findAnnotationDescriptor(SubNonInheritedAnnotationInterface.class, Order.class));
}
@Test
public void findAnnotationDescriptorWithMetaComponentAnnotation() throws Exception {
Class<HasMetaComponentAnnotation> startClass = HasMetaComponentAnnotation.class;
assertComponentOnStereotype(startClass, startClass, "meta1", Meta1.class);
}
@Test
public void findAnnotationDescriptorWithLocalAndMetaComponentAnnotation() throws Exception {
Class<Component> annotationType = Component.class;
AnnotationDescriptor<Component> descriptor = findAnnotationDescriptor(HasLocalAndMetaComponentAnnotation.class,
annotationType);
assertEquals(HasLocalAndMetaComponentAnnotation.class, descriptor.getDeclaringClass());
assertEquals(annotationType, descriptor.getAnnotationType());
assertNull(descriptor.getStereotype());
assertNull(descriptor.getStereotypeType());
}
@Test
public void findAnnotationDescriptorForInterfaceWithMetaAnnotation() {
Class<InterfaceWithMetaAnnotation> startClass = InterfaceWithMetaAnnotation.class;
assertComponentOnStereotype(startClass, startClass, "meta1", Meta1.class);
}
@Test
public void findAnnotationDescriptorForClassWithMetaAnnotatedInterface() {
assertNull(findAnnotationDescriptor(ClassWithMetaAnnotatedInterface.class, Component.class));
}
@Test
public void findAnnotationDescriptorForClassWithLocalMetaAnnotationAndMetaAnnotatedInterface() {
Class<ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface> startClass = ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class;
assertComponentOnStereotype(startClass, startClass, "meta2", Meta2.class);
}
@Test
public void findAnnotationDescriptorForSubClassWithLocalMetaAnnotationAndMetaAnnotatedInterface() {
assertComponentOnStereotype(SubClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class,
ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class, "meta2", Meta2.class);
}
// -------------------------------------------------------------------------
@Test
@SuppressWarnings("unchecked")
public void findAnnotationDescriptorForTypesWithNoAnnotationPresent() throws Exception {
assertNull(findAnnotationDescriptorForTypes(NonAnnotatedInterface.class, Transactional.class, Component.class));
assertNull(findAnnotationDescriptorForTypes(NonAnnotatedClass.class, Transactional.class, Order.class));
}
@Test
@SuppressWarnings("unchecked")
public void findAnnotationDescriptorForTypesWithInheritedAnnotationOnClass() throws Exception {
// Note: @Transactional is inherited
assertEquals(InheritedAnnotationClass.class,
findAnnotationDescriptorForTypes(InheritedAnnotationClass.class, Transactional.class).getDeclaringClass());
assertEquals(
InheritedAnnotationClass.class,
findAnnotationDescriptorForTypes(SubInheritedAnnotationClass.class, Transactional.class).getDeclaringClass());
}
@Test
@SuppressWarnings("unchecked")
public void findAnnotationDescriptorForTypesWithInheritedAnnotationOnInterface() throws Exception {
// Note: @Transactional is inherited
assertEquals(
InheritedAnnotationInterface.class,
findAnnotationDescriptorForTypes(InheritedAnnotationInterface.class, Transactional.class).getDeclaringClass());
assertNull(findAnnotationDescriptorForTypes(SubInheritedAnnotationInterface.class, Transactional.class));
assertNull(findAnnotationDescriptorForTypes(SubSubInheritedAnnotationInterface.class, Transactional.class));
}
@Test
@SuppressWarnings("unchecked")
public void findAnnotationDescriptorForTypesForNonInheritedAnnotationOnClass() throws Exception {
// Note: @Order is not inherited.
assertEquals(NonInheritedAnnotationClass.class,
findAnnotationDescriptorForTypes(NonInheritedAnnotationClass.class, Order.class).getDeclaringClass());
assertEquals(NonInheritedAnnotationClass.class,
findAnnotationDescriptorForTypes(SubNonInheritedAnnotationClass.class, Order.class).getDeclaringClass());
}
@Test
@SuppressWarnings("unchecked")
public void findAnnotationDescriptorForTypesForNonInheritedAnnotationOnInterface() throws Exception {
// Note: @Order is not inherited.
assertEquals(NonInheritedAnnotationInterface.class,
findAnnotationDescriptorForTypes(NonInheritedAnnotationInterface.class, Order.class).getDeclaringClass());
assertNull(findAnnotationDescriptorForTypes(SubNonInheritedAnnotationInterface.class, Order.class));
}
@Test
@SuppressWarnings("unchecked")
public void findAnnotationDescriptorForTypesWithLocalAndMetaComponentAnnotation() throws Exception {
Class<Component> annotationType = Component.class;
UntypedAnnotationDescriptor descriptor = findAnnotationDescriptorForTypes(
HasLocalAndMetaComponentAnnotation.class, Transactional.class, annotationType, Order.class);
assertEquals(HasLocalAndMetaComponentAnnotation.class, descriptor.getDeclaringClass());
assertEquals(annotationType, descriptor.getAnnotationType());
assertNull(descriptor.getStereotype());
assertNull(descriptor.getStereotypeType());
}
@Test
public void findAnnotationDescriptorForTypesWithMetaComponentAnnotation() throws Exception {
Class<HasMetaComponentAnnotation> startClass = HasMetaComponentAnnotation.class;
assertComponentOnStereotypeForMultipleCandidateTypes(startClass, startClass, "meta1", Meta1.class);
}
@Test
public void findAnnotationDescriptorForTypesForInterfaceWithMetaAnnotation() {
Class<InterfaceWithMetaAnnotation> startClass = InterfaceWithMetaAnnotation.class;
assertComponentOnStereotypeForMultipleCandidateTypes(startClass, startClass, "meta1", Meta1.class);
}
@Test
@SuppressWarnings("unchecked")
public void findAnnotationDescriptorForTypesForClassWithMetaAnnotatedInterface() {
assertNull(findAnnotationDescriptorForTypes(ClassWithMetaAnnotatedInterface.class, Service.class,
Component.class, Order.class, Transactional.class));
}
@Test
public void findAnnotationDescriptorForTypesForClassWithLocalMetaAnnotationAndMetaAnnotatedInterface() {
Class<ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface> startClass = ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class;
assertComponentOnStereotypeForMultipleCandidateTypes(startClass, startClass, "meta2", Meta2.class);
}
@Test
public void findAnnotationDescriptorForTypesForSubClassWithLocalMetaAnnotationAndMetaAnnotatedInterface() {
assertComponentOnStereotypeForMultipleCandidateTypes(
SubClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class,
ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class, "meta2", Meta2.class);
}
// -------------------------------------------------------------------------
@Component(value = "meta1")
@Order
@Retention(RetentionPolicy.RUNTIME)
static @interface Meta1 {
}
@Component(value = "meta2")
@Transactional
@Retention(RetentionPolicy.RUNTIME)
static @interface Meta2 {
}
@Meta1
static class HasMetaComponentAnnotation {
}
@Meta1
@Component(value = "local")
@Meta2
static class HasLocalAndMetaComponentAnnotation {
}
@Meta1
static interface InterfaceWithMetaAnnotation {
}
static class ClassWithMetaAnnotatedInterface implements InterfaceWithMetaAnnotation {
}
@Meta2
static class ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface implements InterfaceWithMetaAnnotation {
}
static class SubClassWithLocalMetaAnnotationAndMetaAnnotatedInterface extends
ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface {
}
// -------------------------------------------------------------------------
@Transactional
static interface InheritedAnnotationInterface {
}
static interface SubInheritedAnnotationInterface extends InheritedAnnotationInterface {
}
static interface SubSubInheritedAnnotationInterface extends SubInheritedAnnotationInterface {
}
@Order
static interface NonInheritedAnnotationInterface {
}
static interface SubNonInheritedAnnotationInterface extends NonInheritedAnnotationInterface {
}
static class NonAnnotatedClass {
}
static interface NonAnnotatedInterface {
}
@Transactional
static class InheritedAnnotationClass {
}
static class SubInheritedAnnotationClass extends InheritedAnnotationClass {
}
@Order
static class NonInheritedAnnotationClass {
}
static class SubNonInheritedAnnotationClass extends NonInheritedAnnotationClass {
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -18,6 +18,9 @@ package org.springframework.test.context;
import static org.junit.Assert.assertEquals;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import org.junit.Test;
import org.springframework.test.context.support.AbstractTestExecutionListener;
@@ -42,7 +45,7 @@ public class TestExecutionListenersTests {
@Test
public void verifyNumDefaultListenersRegistered() throws Exception {
TestContextManager testContextManager = new TestContextManager(DefaultListenersExampleTestCase.class);
assertEquals("Verifying the number of registered TestExecutionListeners for DefaultListenersExampleTest.", 4,
assertEquals("Num registered TELs for DefaultListenersExampleTestCase.", 4,
testContextManager.getTestExecutionListeners().size());
}
@@ -50,47 +53,64 @@ public class TestExecutionListenersTests {
public void verifyNumNonInheritedDefaultListenersRegistered() throws Exception {
TestContextManager testContextManager = new TestContextManager(
NonInheritedDefaultListenersExampleTestCase.class);
assertEquals(
"Verifying the number of registered TestExecutionListeners for NonInheritedDefaultListenersExampleTest.",
1, testContextManager.getTestExecutionListeners().size());
assertEquals("Num registered TELs for NonInheritedDefaultListenersExampleTestCase.", 1,
testContextManager.getTestExecutionListeners().size());
}
@Test
public void verifyNumInheritedDefaultListenersRegistered() throws Exception {
TestContextManager testContextManager = new TestContextManager(InheritedDefaultListenersExampleTestCase.class);
assertEquals(
"Verifying the number of registered TestExecutionListeners for InheritedDefaultListenersExampleTest.", 1,
assertEquals("Num registered TELs for InheritedDefaultListenersExampleTestCase.", 1,
testContextManager.getTestExecutionListeners().size());
testContextManager = new TestContextManager(SubInheritedDefaultListenersExampleTestCase.class);
assertEquals(
"Verifying the number of registered TestExecutionListeners for SubInheritedDefaultListenersExampleTest.",
1, testContextManager.getTestExecutionListeners().size());
assertEquals("Num registered TELs for SubInheritedDefaultListenersExampleTestCase.", 1,
testContextManager.getTestExecutionListeners().size());
testContextManager = new TestContextManager(SubSubInheritedDefaultListenersExampleTestCase.class);
assertEquals(
"Verifying the number of registered TestExecutionListeners for SubSubInheritedDefaultListenersExampleTest.",
2, testContextManager.getTestExecutionListeners().size());
assertEquals("Num registered TELs for SubSubInheritedDefaultListenersExampleTestCase.", 2,
testContextManager.getTestExecutionListeners().size());
}
@Test
public void verifyNumListenersRegistered() throws Exception {
TestContextManager testContextManager = new TestContextManager(ExampleTestCase.class);
assertEquals("Verifying the number of registered TestExecutionListeners for ExampleTest.", 3,
assertEquals("Num registered TELs for ExampleTestCase.", 3,
testContextManager.getTestExecutionListeners().size());
}
@Test
public void verifyNumNonInheritedListenersRegistered() throws Exception {
TestContextManager testContextManager = new TestContextManager(NonInheritedListenersExampleTestCase.class);
assertEquals("Verifying the number of registered TestExecutionListeners for NonInheritedListenersExampleTest.",
1, testContextManager.getTestExecutionListeners().size());
assertEquals("Num registered TELs for NonInheritedListenersExampleTestCase.", 1,
testContextManager.getTestExecutionListeners().size());
}
@Test
public void verifyNumInheritedListenersRegistered() throws Exception {
TestContextManager testContextManager = new TestContextManager(InheritedListenersExampleTestCase.class);
assertEquals("Verifying the number of registered TestExecutionListeners for InheritedListenersExampleTest.", 4,
assertEquals("Num registered TELs for InheritedListenersExampleTestCase.", 4,
testContextManager.getTestExecutionListeners().size());
}
@Test
public void verifyNumListenersRegisteredViaMetaAnnotation() throws Exception {
TestContextManager testContextManager = new TestContextManager(MetaExampleTestCase.class);
assertEquals("Num registered TELs for MetaExampleTestCase.", 3,
testContextManager.getTestExecutionListeners().size());
}
@Test
public void verifyNumNonInheritedListenersRegisteredViaMetaAnnotation() throws Exception {
TestContextManager testContextManager = new TestContextManager(MetaNonInheritedListenersExampleTestCase.class);
assertEquals("Num registered TELs for MetaNonInheritedListenersExampleTestCase.", 1,
testContextManager.getTestExecutionListeners().size());
}
@Test
public void verifyNumInheritedListenersRegisteredViaMetaAnnotation() throws Exception {
TestContextManager testContextManager = new TestContextManager(MetaInheritedListenersExampleTestCase.class);
assertEquals("Num registered TELs for MetaInheritedListenersExampleTestCase.", 4,
testContextManager.getTestExecutionListeners().size());
}
@@ -118,7 +138,7 @@ public class TestExecutionListenersTests {
static class NonInheritedDefaultListenersExampleTestCase extends InheritedDefaultListenersExampleTestCase {
}
@TestExecutionListeners( { FooTestExecutionListener.class, BarTestExecutionListener.class,
@TestExecutionListeners({ FooTestExecutionListener.class, BarTestExecutionListener.class,
BazTestExecutionListener.class })
static class ExampleTestCase {
}
@@ -135,6 +155,37 @@ public class TestExecutionListenersTests {
static class DuplicateListenersConfigExampleTestCase {
}
@TestExecutionListeners({//
FooTestExecutionListener.class,//
BarTestExecutionListener.class,//
BazTestExecutionListener.class //
})
@Retention(RetentionPolicy.RUNTIME)
static @interface MetaListeners {
}
@TestExecutionListeners(QuuxTestExecutionListener.class)
@Retention(RetentionPolicy.RUNTIME)
static @interface MetaInheritedListeners {
}
@TestExecutionListeners(listeners = QuuxTestExecutionListener.class, inheritListeners = false)
@Retention(RetentionPolicy.RUNTIME)
static @interface MetaNonInheritedListeners {
}
@MetaListeners
static class MetaExampleTestCase {
}
@MetaInheritedListeners
static class MetaInheritedListenersExampleTestCase extends MetaExampleTestCase {
}
@MetaNonInheritedListeners
static class MetaNonInheritedListenersExampleTestCase extends MetaInheritedListenersExampleTestCase {
}
static class FooTestExecutionListener extends AbstractTestExecutionListener {
}

View File

@@ -19,6 +19,8 @@ package org.springframework.test.context.junit4;
import static org.junit.Assert.*;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.Collection;
import java.util.concurrent.atomic.AtomicInteger;
@@ -77,6 +79,7 @@ public class RepeatedSpringRunnerTests {
{ DefaultRepeatValueRepeatedTestCase.class, 0, 1, 1, 1 },//
{ NegativeRepeatValueRepeatedTestCase.class, 0, 1, 1, 1 },//
{ RepeatedFiveTimesRepeatedTestCase.class, 0, 1, 1, 5 },//
{ RepeatedFiveTimesViaMetaAnnotationRepeatedTestCase.class, 0, 1, 1, 5 },//
{ TimedRepeatedTestCase.class, 3, 4, 4, (5 + 1 + 4 + 10) } //
});
}
@@ -147,6 +150,20 @@ public class RepeatedSpringRunnerTests {
}
}
@Repeat(5)
@Retention(RetentionPolicy.RUNTIME)
private static @interface RepeatedFiveTimes {
}
public static final class RepeatedFiveTimesViaMetaAnnotationRepeatedTestCase extends AbstractRepeatedTestCase {
@Test
@RepeatedFiveTimes
public void repeatedFiveTimes() throws Exception {
incrementInvocationCount();
}
}
/**
* Unit tests for claims raised in <a
* href="http://jira.springframework.org/browse/SPR-6011"

View File

@@ -18,6 +18,9 @@ package org.springframework.test.context.junit4;
import static org.junit.Assert.*;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -51,11 +54,11 @@ public class TimedSpringRunnerTests {
notifier.addListener(listener);
new SpringJUnit4ClassRunner(testClass).run(notifier);
assertEquals("Verifying number of failures for test class [" + testClass + "].", 3,
listener.getTestFailureCount());
assertEquals("Verifying number of tests started for test class [" + testClass + "].", 5,
assertEquals("Verifying number of tests started for test class [" + testClass + "].", 6,
listener.getTestStartedCount());
assertEquals("Verifying number of tests finished for test class [" + testClass + "].", 5,
assertEquals("Verifying number of failures for test class [" + testClass + "].", 4,
listener.getTestFailureCount());
assertEquals("Verifying number of tests finished for test class [" + testClass + "].", 6,
listener.getTestFinishedCount());
}
@@ -91,6 +94,13 @@ public class TimedSpringRunnerTests {
Thread.sleep(20);
}
// Should Fail due to timeout.
@Test
@MetaTimed
public void springTimeoutWithSleepAndMetaAnnotation() throws Exception {
Thread.sleep(20);
}
// Should Fail due to duplicate configuration.
@Test(timeout = 200)
@Timed(millis = 200)
@@ -99,4 +109,9 @@ public class TimedSpringRunnerTests {
}
}
@Timed(millis = 10)
@Retention(RetentionPolicy.RUNTIME)
private static @interface MetaTimed {
}
}

View File

@@ -0,0 +1,201 @@
/*
* Copyright 2002-2013 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.support;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.annotation.DirtiesContext.HierarchyMode;
import org.springframework.test.context.TestContext;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
import static org.springframework.test.annotation.DirtiesContext.HierarchyMode.*;
/**
* Unit tests for {@link DirtiesContextTestExecutionListener}.
*
* @author Sam Brannen
* @since 4.0
*/
public class DirtiesContextTestExecutionListenerTests {
private final DirtiesContextTestExecutionListener listener = new DirtiesContextTestExecutionListener();
private final TestContext testContext = mock(TestContext.class);
@Test
public void afterTestMethodForDirtiesContextDeclaredLocallyOnMethod() throws Exception {
Class<?> clazz = getClass();
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
when(testContext.getTestMethod()).thenReturn(clazz.getDeclaredMethod("dirtiesContextDeclaredLocally"));
listener.afterTestMethod(testContext);
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
}
@Test
public void afterTestMethodForDirtiesContextDeclaredOnMethodViaMetaAnnotation() throws Exception {
Class<?> clazz = getClass();
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
when(testContext.getTestMethod()).thenReturn(clazz.getDeclaredMethod("dirtiesContextDeclaredViaMetaAnnotation"));
listener.afterTestMethod(testContext);
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
}
@Test
public void afterTestMethodForDirtiesContextDeclaredLocallyOnClassAfterEachTestMethod() throws Exception {
Class<?> clazz = DirtiesContextDeclaredLocallyAfterEachTestMethod.class;
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
when(testContext.getTestMethod()).thenReturn(clazz.getDeclaredMethod("clean"));
listener.afterTestMethod(testContext);
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
}
@Test
public void afterTestMethodForDirtiesContextDeclaredViaMetaAnnotationOnClassAfterEachTestMethod() throws Exception {
Class<?> clazz = DirtiesContextDeclaredViaMetaAnnotationAfterEachTestMethod.class;
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
when(testContext.getTestMethod()).thenReturn(clazz.getDeclaredMethod("clean"));
listener.afterTestMethod(testContext);
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
}
@Test
public void afterTestMethodForDirtiesContextDeclaredLocallyOnClassAfterClass() throws Exception {
Class<?> clazz = DirtiesContextDeclaredLocallyAfterClass.class;
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
when(testContext.getTestMethod()).thenReturn(clazz.getDeclaredMethod("clean"));
listener.afterTestMethod(testContext);
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
}
@Test
public void afterTestMethodForDirtiesContextDeclaredViaMetaAnnotationOnClassAfterClass() throws Exception {
Class<?> clazz = DirtiesContextDeclaredViaMetaAnnotationAfterClass.class;
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
when(testContext.getTestMethod()).thenReturn(clazz.getDeclaredMethod("clean"));
listener.afterTestMethod(testContext);
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
}
// -------------------------------------------------------------------------
@Test
public void afterTestClassForDirtiesContextDeclaredLocallyOnMethod() throws Exception {
Class<?> clazz = getClass();
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
listener.afterTestClass(testContext);
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
}
@Test
public void afterTestClassForDirtiesContextDeclaredLocallyOnClassAfterEachTestMethod() throws Exception {
Class<?> clazz = DirtiesContextDeclaredLocallyAfterEachTestMethod.class;
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
listener.afterTestClass(testContext);
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
}
@Test
public void afterTestClassForDirtiesContextDeclaredViaMetaAnnotationOnClassAfterEachTestMethod() throws Exception {
Class<?> clazz = DirtiesContextDeclaredViaMetaAnnotationAfterEachTestMethod.class;
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
listener.afterTestClass(testContext);
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
}
@Test
public void afterTestClassForDirtiesContextDeclaredLocallyOnClassAfterClass() throws Exception {
Class<?> clazz = DirtiesContextDeclaredLocallyAfterClass.class;
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
listener.afterTestClass(testContext);
verify(testContext, times(1)).markApplicationContextDirty(any(HierarchyMode.class));
}
@Test
public void afterTestClassForDirtiesContextDeclaredViaMetaAnnotationOnClassAfterClass() throws Exception {
Class<?> clazz = DirtiesContextDeclaredViaMetaAnnotationAfterClass.class;
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
listener.afterTestClass(testContext);
verify(testContext, times(1)).markApplicationContextDirty(any(HierarchyMode.class));
}
// -------------------------------------------------------------------------
@DirtiesContext
void dirtiesContextDeclaredLocally() {
/* no-op */
}
@MetaDirty
void dirtiesContextDeclaredViaMetaAnnotation() {
/* no-op */
}
@DirtiesContext
@Retention(RetentionPolicy.RUNTIME)
static @interface MetaDirty {
}
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
@Retention(RetentionPolicy.RUNTIME)
static @interface MetaDirtyAfterEachTestMethod {
}
@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
@Retention(RetentionPolicy.RUNTIME)
static @interface MetaDirtyAfterClass {
}
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
static class DirtiesContextDeclaredLocallyAfterEachTestMethod {
void clean() {
/* no-op */
}
}
@MetaDirtyAfterEachTestMethod
static class DirtiesContextDeclaredViaMetaAnnotationAfterEachTestMethod {
void clean() {
/* no-op */
}
}
@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
static class DirtiesContextDeclaredLocallyAfterClass {
void clean() {
/* no-op */
}
}
@MetaDirtyAfterClass
static class DirtiesContextDeclaredViaMetaAnnotationAfterClass {
void clean() {
/* no-op */
}
}
}

View File

@@ -0,0 +1,73 @@
/*
* 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.web;
import java.io.File;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockServletContext;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.context.WebApplicationContext;
import static org.junit.Assert.*;
/**
* Integration test that verifies meta-annotation support for {@link WebAppConfiguration}
* and {@link org.springframework.test.context.ContextConfiguration ContextConfiguration}.
*
* @author Sam Brannen
* @since 4.0
* @see WebTests
*/
@RunWith(SpringJUnit4ClassRunner.class)
@WebTests
public class MetaAnnotationConfigWacTests {
@Autowired
protected WebApplicationContext wac;
@Autowired
protected MockServletContext mockServletContext;
@Autowired
protected String foo;
@Test
public void fooEnigmaAutowired() {
assertEquals("enigma", foo);
}
@Test
public void basicWacFeatures() throws Exception {
assertNotNull("ServletContext should be set in the WAC.", wac.getServletContext());
assertNotNull("ServletContext should have been autowired from the WAC.", mockServletContext);
Object rootWac = mockServletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
assertNotNull("Root WAC must be stored in the ServletContext as: "
+ WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, rootWac);
assertSame("test WAC and Root WAC in ServletContext must be the same object.", wac, rootWac);
assertSame("ServletContext instances must be the same object.", mockServletContext, wac.getServletContext());
assertEquals("Getting real path for ServletContext resource.",
new File("src/main/webapp/index.jsp").getCanonicalPath(), mockServletContext.getRealPath("index.jsp"));
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2002-2013 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.web;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
/**
* Custom stereotype combining {@link WebAppConfiguration} and
* {@link ContextConfiguration} as meta-annotations.
*
* @author Sam Brannen
* @since 4.0
*/
@WebAppConfiguration
@ContextConfiguration
@Retention(RetentionPolicy.RUNTIME)
public @interface WebTests {
@Configuration
static class Config {
@Bean
public String foo() {
return "enigma";
}
}
}