28 changed files with 1852 additions and 205 deletions
@ -0,0 +1,248 @@
@@ -0,0 +1,248 @@
|
||||
/* |
||||
* 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 org.springframework.core.style.ToStringCreator; |
||||
import org.springframework.util.Assert; |
||||
import org.springframework.util.ObjectUtils; |
||||
|
||||
import static org.springframework.core.annotation.AnnotationUtils.*; |
||||
|
||||
/** |
||||
* TODO Document MetaAnnotationUtils. |
||||
* |
||||
* @author Sam Brannen |
||||
* @since 4.0 |
||||
*/ |
||||
abstract class MetaAnnotationUtils { |
||||
|
||||
private MetaAnnotationUtils() { |
||||
/* no-op */ |
||||
} |
||||
|
||||
/** |
||||
* TODO Document findAnnotationDescriptor(). |
||||
* |
||||
* @param clazz the class to look for annotations on |
||||
* @param annotationType the annotation class to look for, both locally and |
||||
* as a meta-annotation |
||||
* @return the corresponding annotation descriptor if the annotation was found; |
||||
* otherwise {@code null} |
||||
*/ |
||||
public static <T extends Annotation> AnnotationDescriptor<T> findAnnotationDescriptor(Class<?> clazz, |
||||
Class<T> annotationType) { |
||||
|
||||
Assert.notNull(annotationType, "Annotation type must not be null"); |
||||
|
||||
if (clazz == null || clazz.equals(Object.class)) { |
||||
return null; |
||||
} |
||||
|
||||
// Declared locally?
|
||||
if (isAnnotationDeclaredLocally(annotationType, clazz)) { |
||||
return new AnnotationDescriptor<T>(clazz, clazz.getAnnotation(annotationType)); |
||||
} |
||||
|
||||
// Declared on a stereotype annotation (i.e., as a meta-annotation)?
|
||||
if (!Annotation.class.isAssignableFrom(clazz)) { |
||||
for (Annotation stereotype : clazz.getAnnotations()) { |
||||
T annotation = stereotype.annotationType().getAnnotation(annotationType); |
||||
if (annotation != null) { |
||||
return new AnnotationDescriptor<T>(clazz, stereotype, annotation); |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Declared on a superclass?
|
||||
return findAnnotationDescriptor(clazz.getSuperclass(), annotationType); |
||||
} |
||||
|
||||
/** |
||||
* TODO Document findAnnotationDescriptorForTypes(). |
||||
* |
||||
* @param clazz the class to look for annotations on |
||||
* @param annotationTypes the types of annotations to look for, both locally |
||||
* and as meta-annotations |
||||
* @return the corresponding annotation descriptor if one of the annotations |
||||
* was found; otherwise {@code null} |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public static UntypedAnnotationDescriptor findAnnotationDescriptorForTypes(Class<?> clazz, |
||||
Class<? extends Annotation>... annotationTypes) { |
||||
|
||||
assertNonEmptyAnnotationTypeArray(annotationTypes, "The list of annotation types must not be empty"); |
||||
|
||||
if (clazz == null || clazz.equals(Object.class)) { |
||||
return null; |
||||
} |
||||
|
||||
// Declared locally?
|
||||
for (Class<? extends Annotation> annotationType : annotationTypes) { |
||||
if (isAnnotationDeclaredLocally(annotationType, clazz)) { |
||||
return new UntypedAnnotationDescriptor(clazz, clazz.getAnnotation(annotationType)); |
||||
} |
||||
} |
||||
|
||||
// Declared on a stereotype annotation (i.e., as a meta-annotation)?
|
||||
if (!Annotation.class.isAssignableFrom(clazz)) { |
||||
for (Annotation stereotype : clazz.getAnnotations()) { |
||||
for (Class<? extends Annotation> annotationType : annotationTypes) { |
||||
Annotation annotation = stereotype.annotationType().getAnnotation(annotationType); |
||||
if (annotation != null) { |
||||
return new UntypedAnnotationDescriptor(clazz, stereotype, annotation); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Declared on a superclass?
|
||||
return findAnnotationDescriptorForTypes(clazz.getSuperclass(), annotationTypes); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Descriptor for an {@link Annotation}, including the {@linkplain |
||||
* #getDeclaringClass() class} on which the annotation is <em>declared</em> |
||||
* as well as the actual {@linkplain #getAnnotation() annotation} instance. |
||||
* |
||||
* <p> |
||||
* If the annotation is used as a meta-annotation, the descriptor also includes |
||||
* the {@linkplain #getStereotype() stereotype} on which the annotation is |
||||
* present. In such cases, the <em>declaring class</em> is not directly |
||||
* annotated with the annotation but rather indirectly via the stereotype. |
||||
* |
||||
* <p> |
||||
* Given the following example, if we are searching for the {@code @Transactional} |
||||
* annotation <em>on</em> the {@code TransactionalTests} class, then the |
||||
* properties of the {@code AnnotationDescriptor} would be as follows. |
||||
* |
||||
* <ul> |
||||
* <li>declaringClass: {@code TransactionalTests} class object</li> |
||||
* <li>stereotype: {@code null}</li> |
||||
* <li>annotation: instance of the {@code Transactional} annotation</li> |
||||
* </ul> |
||||
* |
||||
* <pre style="code"> |
||||
* @Transactional |
||||
* @ContextConfiguration({"/test-datasource.xml", "/repository-config.xml"}) |
||||
* public class TransactionalTests { } |
||||
* </pre> |
||||
* |
||||
* <p> |
||||
* Given the following example, if we are searching for the {@code @Transactional} |
||||
* annotation <em>on</em> the {@code UserRepositoryTests} class, then the |
||||
* properties of the {@code AnnotationDescriptor} would be as follows. |
||||
* |
||||
* <ul> |
||||
* <li>declaringClass: {@code UserRepositoryTests} class object</li> |
||||
* <li>stereotype: instance of the {@code RepositoryTests} annotation</li> |
||||
* <li>annotation: instance of the {@code Transactional} annotation</li> |
||||
* </ul> |
||||
* |
||||
* <pre style="code"> |
||||
* @Transactional |
||||
* @ContextConfiguration({"/test-datasource.xml", "/repository-config.xml"}) |
||||
* @Retention(RetentionPolicy.RUNTIME) |
||||
* public @interface RepositoryTests { } |
||||
* |
||||
* @RepositoryTests |
||||
* public class UserRepositoryTests { } |
||||
* </pre> |
||||
* |
||||
* @author Sam Brannen |
||||
* @since 4.0 |
||||
*/ |
||||
public static class AnnotationDescriptor<T extends Annotation> { |
||||
|
||||
private final Class<?> declaringClass; |
||||
private final Annotation stereotype; |
||||
private final T annotation; |
||||
|
||||
|
||||
public AnnotationDescriptor(Class<?> declaringClass, T annotation) { |
||||
this(declaringClass, null, annotation); |
||||
} |
||||
|
||||
public AnnotationDescriptor(Class<?> declaringClass, Annotation stereotype, T annotation) { |
||||
Assert.notNull(declaringClass, "declaringClass must not be null"); |
||||
Assert.notNull(annotation, "annotation must not be null"); |
||||
|
||||
this.declaringClass = declaringClass; |
||||
this.stereotype = stereotype; |
||||
this.annotation = annotation; |
||||
} |
||||
|
||||
public Class<?> getDeclaringClass() { |
||||
return this.declaringClass; |
||||
} |
||||
|
||||
public T getAnnotation() { |
||||
return this.annotation; |
||||
} |
||||
|
||||
public Class<? extends Annotation> getAnnotationType() { |
||||
return this.annotation.annotationType(); |
||||
} |
||||
|
||||
public Annotation getStereotype() { |
||||
return this.stereotype; |
||||
} |
||||
|
||||
public Class<? extends Annotation> getStereotypeType() { |
||||
return this.stereotype == null ? null : this.stereotype.annotationType(); |
||||
} |
||||
|
||||
/** |
||||
* Provide a textual representation of this {@code AnnotationDescriptor}. |
||||
*/ |
||||
@Override |
||||
public String toString() { |
||||
return new ToStringCreator(this)//
|
||||
.append("declaringClass", declaringClass)//
|
||||
.append("stereotype", stereotype)//
|
||||
.append("annotation", annotation)//
|
||||
.toString(); |
||||
} |
||||
} |
||||
|
||||
public static class UntypedAnnotationDescriptor extends AnnotationDescriptor<Annotation> { |
||||
|
||||
public UntypedAnnotationDescriptor(Class<?> declaringClass, Annotation annotation) { |
||||
super(declaringClass, annotation); |
||||
} |
||||
|
||||
public UntypedAnnotationDescriptor(Class<?> declaringClass, Annotation stereotype, Annotation annotation) { |
||||
super(declaringClass, stereotype, annotation); |
||||
} |
||||
} |
||||
|
||||
|
||||
private static void assertNonEmptyAnnotationTypeArray(Class<?>[] annotationTypes, String message) { |
||||
if (ObjectUtils.isEmpty(annotationTypes)) { |
||||
throw new IllegalArgumentException(message); |
||||
} |
||||
|
||||
for (Class clazz : annotationTypes) { |
||||
if (!Annotation.class.isAssignableFrom(clazz)) { |
||||
throw new IllegalArgumentException("Array elements must be of type Annotation"); |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,307 @@
@@ -0,0 +1,307 @@
|
||||
/* |
||||
* 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.transaction; |
||||
|
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
|
||||
import org.junit.Test; |
||||
import org.mockito.Mockito; |
||||
import org.springframework.test.context.TestContext; |
||||
import org.springframework.transaction.PlatformTransactionManager; |
||||
import org.springframework.transaction.TransactionDefinition; |
||||
import org.springframework.transaction.annotation.Transactional; |
||||
import org.springframework.transaction.support.SimpleTransactionStatus; |
||||
|
||||
import static org.junit.Assert.*; |
||||
import static org.mockito.Mockito.*; |
||||
|
||||
/** |
||||
* Unit tests for {@link TransactionalTestExecutionListener}. |
||||
* |
||||
* @author Sam Brannen |
||||
* @since 4.0 |
||||
*/ |
||||
public class TransactionalTestExecutionListenerTests { |
||||
|
||||
private final PlatformTransactionManager tm = mock(PlatformTransactionManager.class); |
||||
|
||||
private final TransactionalTestExecutionListener listener = new TransactionalTestExecutionListener() { |
||||
|
||||
protected PlatformTransactionManager getTransactionManager(TestContext testContext, String qualifier) { |
||||
return tm; |
||||
} |
||||
}; |
||||
|
||||
private final TestContext testContext = mock(TestContext.class); |
||||
|
||||
|
||||
private void assertBeforeTestMethod(Class<? extends Invocable> clazz) throws Exception { |
||||
assertBeforeTestMethodWithTransactionalTestMethod(clazz); |
||||
assertBeforeTestMethodWithNonTransactionalTestMethod(clazz); |
||||
} |
||||
|
||||
private void assertBeforeTestMethodWithTransactionalTestMethod(Class<? extends Invocable> clazz) throws Exception { |
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz); |
||||
Invocable instance = clazz.newInstance(); |
||||
when(testContext.getTestInstance()).thenReturn(instance); |
||||
when(testContext.getTestMethod()).thenReturn(clazz.getDeclaredMethod("transactionalTest")); |
||||
|
||||
assertFalse(instance.invoked); |
||||
listener.beforeTestMethod(testContext); |
||||
assertTrue(instance.invoked); |
||||
} |
||||
|
||||
private void assertBeforeTestMethodWithNonTransactionalTestMethod(Class<? extends Invocable> clazz) |
||||
throws Exception { |
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz); |
||||
Invocable instance = clazz.newInstance(); |
||||
when(testContext.getTestInstance()).thenReturn(instance); |
||||
when(testContext.getTestMethod()).thenReturn(clazz.getDeclaredMethod("nonTransactionalTest")); |
||||
|
||||
assertFalse(instance.invoked); |
||||
listener.beforeTestMethod(testContext); |
||||
assertFalse(instance.invoked); |
||||
} |
||||
|
||||
private void assertAfterTestMethod(Class<? extends Invocable> clazz) throws Exception { |
||||
assertAfterTestMethodWithTransactionalTestMethod(clazz); |
||||
assertAfterTestMethodWithNonTransactionalTestMethod(clazz); |
||||
} |
||||
|
||||
private void assertAfterTestMethodWithTransactionalTestMethod(Class<? extends Invocable> clazz) throws Exception { |
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz); |
||||
Invocable instance = clazz.newInstance(); |
||||
when(testContext.getTestInstance()).thenReturn(instance); |
||||
when(testContext.getTestMethod()).thenReturn(clazz.getDeclaredMethod("transactionalTest")); |
||||
|
||||
when(tm.getTransaction(Mockito.any(TransactionDefinition.class))).thenReturn(new SimpleTransactionStatus()); |
||||
|
||||
assertFalse(instance.invoked); |
||||
listener.beforeTestMethod(testContext); |
||||
listener.afterTestMethod(testContext); |
||||
assertTrue(instance.invoked); |
||||
} |
||||
|
||||
private void assertAfterTestMethodWithNonTransactionalTestMethod(Class<? extends Invocable> clazz) throws Exception { |
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz); |
||||
Invocable instance = clazz.newInstance(); |
||||
when(testContext.getTestInstance()).thenReturn(instance); |
||||
when(testContext.getTestMethod()).thenReturn(clazz.getDeclaredMethod("nonTransactionalTest")); |
||||
|
||||
assertFalse(instance.invoked); |
||||
listener.beforeTestMethod(testContext); |
||||
listener.afterTestMethod(testContext); |
||||
assertFalse(instance.invoked); |
||||
} |
||||
|
||||
@Test |
||||
public void beforeTestMethodWithTransactionalDeclaredOnClassLocally() throws Exception { |
||||
assertBeforeTestMethodWithTransactionalTestMethod(TransactionalDeclaredOnClassLocallyTestCase.class); |
||||
} |
||||
|
||||
@Test |
||||
public void beforeTestMethodWithTransactionalDeclaredOnClassViaMetaAnnotation() throws Exception { |
||||
assertBeforeTestMethodWithTransactionalTestMethod(TransactionalDeclaredOnClassViaMetaAnnotationTestCase.class); |
||||
} |
||||
|
||||
@Test |
||||
public void beforeTestMethodWithTransactionalDeclaredOnMethodLocally() throws Exception { |
||||
assertBeforeTestMethod(TransactionalDeclaredOnMethodLocallyTestCase.class); |
||||
} |
||||
|
||||
@Test |
||||
public void beforeTestMethodWithTransactionalDeclaredOnMethodViaMetaAnnotation() throws Exception { |
||||
assertBeforeTestMethod(TransactionalDeclaredOnMethodViaMetaAnnotationTestCase.class); |
||||
} |
||||
|
||||
@Test |
||||
public void beforeTestMethodWithBeforeTransactionDeclaredLocally() throws Exception { |
||||
assertBeforeTestMethod(BeforeTransactionDeclaredLocallyTestCase.class); |
||||
} |
||||
|
||||
@Test |
||||
public void beforeTestMethodWithBeforeTransactionDeclaredViaMetaAnnotation() throws Exception { |
||||
assertBeforeTestMethod(BeforeTransactionDeclaredViaMetaAnnotationTestCase.class); |
||||
} |
||||
|
||||
@Test |
||||
public void afterTestMethodWithAfterTransactionDeclaredLocally() throws Exception { |
||||
assertAfterTestMethod(AfterTransactionDeclaredLocallyTestCase.class); |
||||
} |
||||
|
||||
@Test |
||||
public void afterTestMethodWithAfterTransactionDeclaredViaMetaAnnotation() throws Exception { |
||||
assertAfterTestMethod(AfterTransactionDeclaredViaMetaAnnotationTestCase.class); |
||||
} |
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Transactional |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
private static @interface MetaTransactional { |
||||
} |
||||
|
||||
@BeforeTransaction |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
private static @interface MetaBeforeTransaction { |
||||
} |
||||
|
||||
@AfterTransaction |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
private static @interface MetaAfterTransaction { |
||||
} |
||||
|
||||
private static abstract class Invocable { |
||||
|
||||
boolean invoked = false; |
||||
} |
||||
|
||||
@Transactional |
||||
static class TransactionalDeclaredOnClassLocallyTestCase extends Invocable { |
||||
|
||||
@BeforeTransaction |
||||
public void beforeTransaction() { |
||||
invoked = true; |
||||
} |
||||
|
||||
public void transactionalTest() { |
||||
/* no-op */ |
||||
} |
||||
} |
||||
|
||||
static class TransactionalDeclaredOnMethodLocallyTestCase extends Invocable { |
||||
|
||||
@BeforeTransaction |
||||
public void beforeTransaction() { |
||||
invoked = true; |
||||
} |
||||
|
||||
@Transactional |
||||
public void transactionalTest() { |
||||
/* no-op */ |
||||
} |
||||
|
||||
public void nonTransactionalTest() { |
||||
/* no-op */ |
||||
} |
||||
} |
||||
|
||||
@MetaTransactional |
||||
static class TransactionalDeclaredOnClassViaMetaAnnotationTestCase extends Invocable { |
||||
|
||||
@BeforeTransaction |
||||
public void beforeTransaction() { |
||||
invoked = true; |
||||
} |
||||
|
||||
public void transactionalTest() { |
||||
/* no-op */ |
||||
} |
||||
|
||||
public void nonTransactionalTest() { |
||||
/* no-op */ |
||||
} |
||||
} |
||||
|
||||
static class TransactionalDeclaredOnMethodViaMetaAnnotationTestCase extends Invocable { |
||||
|
||||
@BeforeTransaction |
||||
public void beforeTransaction() { |
||||
invoked = true; |
||||
} |
||||
|
||||
@MetaTransactional |
||||
public void transactionalTest() { |
||||
/* no-op */ |
||||
} |
||||
|
||||
public void nonTransactionalTest() { |
||||
/* no-op */ |
||||
} |
||||
} |
||||
|
||||
static class BeforeTransactionDeclaredLocallyTestCase extends Invocable { |
||||
|
||||
@BeforeTransaction |
||||
public void beforeTransaction() { |
||||
invoked = true; |
||||
} |
||||
|
||||
@Transactional |
||||
public void transactionalTest() { |
||||
/* no-op */ |
||||
} |
||||
|
||||
public void nonTransactionalTest() { |
||||
/* no-op */ |
||||
} |
||||
} |
||||
|
||||
static class BeforeTransactionDeclaredViaMetaAnnotationTestCase extends Invocable { |
||||
|
||||
@MetaBeforeTransaction |
||||
public void beforeTransaction() { |
||||
invoked = true; |
||||
} |
||||
|
||||
@Transactional |
||||
public void transactionalTest() { |
||||
/* no-op */ |
||||
} |
||||
|
||||
public void nonTransactionalTest() { |
||||
/* no-op */ |
||||
} |
||||
} |
||||
|
||||
static class AfterTransactionDeclaredLocallyTestCase extends Invocable { |
||||
|
||||
@AfterTransaction |
||||
public void afterTransaction() { |
||||
invoked = true; |
||||
} |
||||
|
||||
@Transactional |
||||
public void transactionalTest() { |
||||
/* no-op */ |
||||
} |
||||
|
||||
public void nonTransactionalTest() { |
||||
/* no-op */ |
||||
} |
||||
} |
||||
|
||||
static class AfterTransactionDeclaredViaMetaAnnotationTestCase extends Invocable { |
||||
|
||||
@MetaAfterTransaction |
||||
public void afterTransaction() { |
||||
invoked = true; |
||||
} |
||||
|
||||
@Transactional |
||||
public void transactionalTest() { |
||||
/* no-op */ |
||||
} |
||||
|
||||
public void nonTransactionalTest() { |
||||
/* no-op */ |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,321 @@
@@ -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 { |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,201 @@
@@ -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 */ |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,73 @@
@@ -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")); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,46 @@
@@ -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"; |
||||
} |
||||
} |
||||
} |
||||
Loading…
Reference in new issue