Browse Source

Merge from sbrannen/SPR-10338

* SPR-10338:
  Introduce ActiveProfilesResolver in the TCF
pull/640/head
Sam Brannen 13 years ago
parent
commit
4542f362eb
  1. 24
      spring-test/src/main/java/org/springframework/test/context/ActiveProfiles.java
  2. 50
      spring-test/src/main/java/org/springframework/test/context/ActiveProfilesResolver.java
  3. 84
      spring-test/src/main/java/org/springframework/test/context/ContextLoaderUtils.java
  4. 15
      spring-test/src/test/java/org/springframework/test/context/ContextCacheTests.java
  5. 173
      spring-test/src/test/java/org/springframework/test/context/ContextLoaderUtilsTests.java
  6. 4
      spring-test/src/test/java/org/springframework/test/context/junit4/SpringJUnit4TestSuite.java
  7. 34
      spring-test/src/test/java/org/springframework/test/context/junit4/profile/annotation/DevProfileResolverAnnotationConfigTests.java
  8. 5
      spring-test/src/test/java/org/springframework/test/context/junit4/profile/annotation/ProfileAnnotationConfigTestSuite.java
  9. 34
      spring-test/src/test/java/org/springframework/test/context/junit4/profile/importresource/DevProfileResolverAnnotationConfigTests.java
  10. 31
      spring-test/src/test/java/org/springframework/test/context/junit4/profile/resolver/ClassNameActiveProfilesResolver.java
  11. 57
      spring-test/src/test/java/org/springframework/test/context/junit4/profile/resolver/ClassNameActiveProfilesResolverTest.java
  12. 34
      spring-test/src/test/java/org/springframework/test/context/junit4/profile/xml/DevProfileResolverXmlConfigTests.java
  13. 5
      spring-test/src/test/java/org/springframework/test/context/junit4/profile/xml/ProfileXmlConfigTestSuite.java
  14. 318
      src/reference/docbook/testing.xml

24
spring-test/src/main/java/org/springframework/test/context/ActiveProfiles.java

@ -1,5 +1,5 @@ @@ -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.
@ -34,6 +34,7 @@ import java.lang.annotation.Target; @@ -34,6 +34,7 @@ import java.lang.annotation.Target;
* @see SmartContextLoader
* @see MergedContextConfiguration
* @see ContextConfiguration
* @see ActiveProfilesResolver
* @see org.springframework.context.ApplicationContext
* @see org.springframework.context.annotation.Profile
*/
@ -47,8 +48,8 @@ public @interface ActiveProfiles { @@ -47,8 +48,8 @@ public @interface ActiveProfiles {
* Alias for {@link #profiles}.
*
* <p>This attribute may <strong>not</strong> be used in conjunction
* with {@link #profiles}, but it may be used <em>instead</em> of
* {@link #profiles}.
* with {@link #profiles} or {@link #resolver}, but it may be used
* <em>instead</em> of them.
*/
String[] value() default {};
@ -56,11 +57,24 @@ public @interface ActiveProfiles { @@ -56,11 +57,24 @@ public @interface ActiveProfiles {
* The bean definition profiles to activate.
*
* <p>This attribute may <strong>not</strong> be used in conjunction
* with {@link #value}, but it may be used <em>instead</em> of
* {@link #value}.
* with {@link #value} or {@link #resolver}, but it may be used
* <em>instead</em> of them.
*/
String[] profiles() default {};
/**
* The type of {@link ActiveProfilesResolver} to use for resolving the active
* bean definition profiles programmatically.
*
* <p>This attribute may <strong>not</strong> be used in conjunction
* with {@link #profiles} or {@link #value}, but it may be used <em>instead</em>
* of them in order to resolve the active profiles programmatically.
*
* @since 4.0
* @see ActiveProfilesResolver
*/
Class<? extends ActiveProfilesResolver> resolver() default ActiveProfilesResolver.class;
/**
* Whether or not bean definition profiles from superclasses should be
* <em>inherited</em>.

50
spring-test/src/main/java/org/springframework/test/context/ActiveProfilesResolver.java

@ -0,0 +1,50 @@ @@ -0,0 +1,50 @@
/*
* 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;
/**
* Strategy interface for programmatically resolving which <em>active bean
* definition profiles</em> should be used when loading an
* {@link org.springframework.context.ApplicationContext ApplicationContext}
* for a test class.
*
* <p>A custom {@code ActiveProfilesResolver} can be registered via the
* {@link ActiveProfiles#resolver resolver} attribute of {@code @ActiveProfiles}.
*
* <p>Concrete implementations must provide a {@code public} no-args constructor.
*
* @author Sam Brannen
* @author Michail Nikolaev
* @since 4.0
* @see ActiveProfiles
*/
public interface ActiveProfilesResolver {
/**
* Resolve the <em>bean definition profiles</em> to use when loading an
* {@code ApplicationContext} for the given {@linkplain Class test class}.
*
* @param testClass the test class for which the profiles should be resolved;
* never {@code null}
* @return the list of bean definition profiles to use when loading the
* {@code ApplicationContext}; never {@code null}
* @see ActiveProfiles#resolver
* @see ActiveProfiles#inheritProfiles
*/
String[] resolve(Class<?> testClass);
}

84
spring-test/src/main/java/org/springframework/test/context/ContextLoaderUtils.java

@ -16,11 +16,6 @@ @@ -16,11 +16,6 @@
package org.springframework.test.context;
import static org.springframework.beans.BeanUtils.instantiateClass;
import static org.springframework.core.annotation.AnnotationUtils.findAnnotationDeclaringClass;
import static org.springframework.core.annotation.AnnotationUtils.findAnnotationDeclaringClassForTypes;
import static org.springframework.core.annotation.AnnotationUtils.isAnnotationDeclaredLocally;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
@ -42,6 +37,9 @@ import org.springframework.util.ClassUtils; @@ -42,6 +37,9 @@ import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import static org.springframework.beans.BeanUtils.*;
import static org.springframework.core.annotation.AnnotationUtils.*;
/**
* Utility methods for working with {@link ContextLoader ContextLoaders} and
* {@link SmartContextLoader SmartContextLoaders} and resolving resource locations,
@ -49,12 +47,14 @@ import org.springframework.util.StringUtils; @@ -49,12 +47,14 @@ import org.springframework.util.StringUtils;
* initializers.
*
* @author Sam Brannen
* @author Michail Nikolaev
* @since 3.1
* @see ContextLoader
* @see SmartContextLoader
* @see ContextConfiguration
* @see ContextConfigurationAttributes
* @see ActiveProfiles
* @see ActiveProfilesResolver
* @see ApplicationContextInitializer
* @see ContextHierarchy
* @see MergedContextConfiguration
@ -477,24 +477,43 @@ abstract class ContextLoaderUtils { @@ -477,24 +477,43 @@ abstract class ContextLoaderUtils {
while (declaringClass != null) {
ActiveProfiles annotation = declaringClass.getAnnotation(annotationType);
if (logger.isTraceEnabled()) {
logger.trace(String.format("Retrieved @ActiveProfiles [%s] for declaring class [%s].", annotation,
declaringClass.getName()));
}
validateActiveProfilesConfiguration(declaringClass, annotation);
String[] profiles = annotation.profiles();
String[] valueProfiles = annotation.value();
Class<? extends ActiveProfilesResolver> resolverClass = annotation.resolver();
if (!ObjectUtils.isEmpty(valueProfiles) && !ObjectUtils.isEmpty(profiles)) {
String msg = String.format("Test class [%s] has been configured with @ActiveProfiles' 'value' [%s] "
+ "and 'profiles' [%s] attributes. Only one declaration of active bean "
+ "definition profiles is permitted per @ActiveProfiles annotation.", declaringClass.getName(),
ObjectUtils.nullSafeToString(valueProfiles), ObjectUtils.nullSafeToString(profiles));
logger.error(msg);
throw new IllegalStateException(msg);
boolean resolverDeclared = !ActiveProfilesResolver.class.equals(resolverClass);
boolean valueDeclared = !ObjectUtils.isEmpty(valueProfiles);
if (resolverDeclared) {
ActiveProfilesResolver resolver = null;
try {
resolver = instantiateClass(resolverClass, ActiveProfilesResolver.class);
}
catch (Exception e) {
String msg = String.format("Could not instantiate ActiveProfilesResolver of "
+ "type [%s] for test class [%s].", resolverClass.getName(), declaringClass.getName());
logger.error(msg);
throw new IllegalStateException(msg, e);
}
if (resolver != null) {
profiles = resolver.resolve(declaringClass);
if (profiles == null) {
String msg = String.format(
"ActiveProfilesResolver [%s] returned a null array of bean definition profiles.",
resolverClass.getName());
logger.error(msg);
throw new IllegalStateException(msg);
}
}
}
else if (!ObjectUtils.isEmpty(valueProfiles)) {
else if (valueDeclared) {
profiles = valueProfiles;
}
@ -511,6 +530,43 @@ abstract class ContextLoaderUtils { @@ -511,6 +530,43 @@ abstract class ContextLoaderUtils {
return StringUtils.toStringArray(activeProfiles);
}
private static void validateActiveProfilesConfiguration(Class<?> declaringClass, ActiveProfiles annotation) {
String[] valueProfiles = annotation.value();
String[] profiles = annotation.profiles();
Class<? extends ActiveProfilesResolver> resolverClass = annotation.resolver();
boolean valueDeclared = !ObjectUtils.isEmpty(valueProfiles);
boolean profilesDeclared = !ObjectUtils.isEmpty(profiles);
boolean resolverDeclared = !ActiveProfilesResolver.class.equals(resolverClass);
String msg = null;
if (valueDeclared && profilesDeclared) {
msg = String.format("Test class [%s] has been configured with @ActiveProfiles' 'value' [%s] "
+ "and 'profiles' [%s] attributes. Only one declaration of active bean "
+ "definition profiles is permitted per @ActiveProfiles annotation.", declaringClass.getName(),
ObjectUtils.nullSafeToString(valueProfiles), ObjectUtils.nullSafeToString(profiles));
}
else if (valueDeclared && resolverDeclared) {
msg = String.format("Test class [%s] has been configured with @ActiveProfiles' 'value' [%s] "
+ "and 'resolver' [%s] attributes. Only one source of active bean "
+ "definition profiles is permitted per @ActiveProfiles annotation, "
+ "either declaritively or programmatically.", declaringClass.getName(),
ObjectUtils.nullSafeToString(valueProfiles), resolverClass.getName());
}
else if (profilesDeclared && resolverDeclared) {
msg = String.format("Test class [%s] has been configured with @ActiveProfiles' 'profiles' [%s] "
+ "and 'resolver' [%s] attributes. Only one source of active bean "
+ "definition profiles is permitted per @ActiveProfiles annotation, "
+ "either declaritively or programmatically.", declaringClass.getName(),
ObjectUtils.nullSafeToString(profiles), resolverClass.getName());
}
if (msg != null) {
logger.error(msg);
throw new IllegalStateException(msg);
}
}
/**
* Build the {@link MergedContextConfiguration merged context configuration} for
* the supplied {@link Class testClass} and {@code defaultContextLoaderClassName},

15
spring-test/src/test/java/org/springframework/test/context/ContextCacheTests.java

@ -32,6 +32,7 @@ import static org.springframework.test.context.SpringRunnerContextCacheTests.*; @@ -32,6 +32,7 @@ import static org.springframework.test.context.SpringRunnerContextCacheTests.*;
* conjunction with cache keys used in {@link TestContext}.
*
* @author Sam Brannen
* @author Michail Nikolaev
* @since 3.1
* @see SpringRunnerContextCacheTests
*/
@ -84,6 +85,7 @@ public class ContextCacheTests { @@ -84,6 +85,7 @@ public class ContextCacheTests {
loadCtxAndAssertStats(FooBarProfilesTestCase.class, 1, 3, 1);
loadCtxAndAssertStats(FooBarProfilesTestCase.class, 1, 4, 1);
loadCtxAndAssertStats(BarFooProfilesTestCase.class, 1, 5, 1);
loadCtxAndAssertStats(FooBarActiveProfilesResolverTestCase.class, 1, 6, 1);
}
@Test
@ -287,6 +289,19 @@ public class ContextCacheTests { @@ -287,6 +289,19 @@ public class ContextCacheTests {
private static class BarFooProfilesTestCase {
}
private static class FooBarActiveProfilesResolver implements ActiveProfilesResolver {
@Override
public String[] resolve(Class<?> testClass) {
return new String[] { "foo", "bar" };
}
}
@ActiveProfiles(resolver = FooBarActiveProfilesResolver.class)
@ContextConfiguration(classes = Config.class, loader = AnnotationConfigContextLoader.class)
private static class FooBarActiveProfilesResolverTestCase {
}
@ContextHierarchy({ @ContextConfiguration })
private static class ClassHierarchyContextHierarchyLevel1TestCase {

173
spring-test/src/test/java/org/springframework/test/context/ContextLoaderUtilsTests.java

@ -16,10 +16,6 @@ @@ -16,10 +16,6 @@
package org.springframework.test.context;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.springframework.test.context.ContextLoaderUtils.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
@ -38,10 +34,15 @@ import org.springframework.test.context.support.DelegatingSmartContextLoader; @@ -38,10 +34,15 @@ import org.springframework.test.context.support.DelegatingSmartContextLoader;
import org.springframework.test.context.support.GenericPropertiesContextLoader;
import org.springframework.web.context.support.GenericWebApplicationContext;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.springframework.test.context.ContextLoaderUtils.*;
/**
* Unit tests for {@link ContextLoaderUtils}.
*
* @author Sam Brannen
* @author Michail Nikolaev
* @since 3.1
*/
public class ContextLoaderUtilsTests {
@ -606,8 +607,94 @@ public class ContextLoaderUtilsTests { @@ -606,8 +607,94 @@ public class ContextLoaderUtilsTests {
assertTrue(list.contains("cat"));
}
/**
* @since 4.0
*/
@Test
public void resolveActiveProfilesWithResolver() {
String[] profiles = resolveActiveProfiles(FooActiveProfilesResolverTest.class);
assertNotNull(profiles);
assertEquals(1, profiles.length);
assertArrayEquals(new String[] { "foo" }, profiles);
}
/**
* @since 4.0
*/
@Test
public void resolveActiveProfilesWithInheritedResolver() {
String[] profiles = resolveActiveProfiles(InheritedFooActiveProfilesResolverTest.class);
assertNotNull(profiles);
assertEquals(1, profiles.length);
assertArrayEquals(new String[] { "foo" }, profiles);
}
/**
* @since 4.0
*/
@Test
public void resolveActiveProfilesWithMergedInheritedResolver() {
String[] profiles = resolveActiveProfiles(MergedInheritedFooActiveProfilesResolverTest.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 resolveActiveProfilesWithOverridenInheritedResolver() {
String[] profiles = resolveActiveProfiles(OverridenInheritedFooActiveProfilesResolverTest.class);
assertNotNull(profiles);
assertEquals(1, profiles.length);
assertArrayEquals(new String[] { "bar" }, profiles);
}
/**
* @since 4.0
*/
@Test(expected = IllegalStateException.class)
public void resolveActiveProfilesWithConflictingResolverAndProfiles() {
resolveActiveProfiles(ConflictingResolverAndProfilesTest.class);
}
/**
* @since 4.0
*/
@Test(expected = IllegalStateException.class)
public void resolveActiveProfilesWithConflictingResolverAndValue() {
resolveActiveProfiles(ConflictingResolverAndValueTest.class);
}
/**
* @since 4.0
*/
@Test(expected = IllegalStateException.class)
public void resolveActiveProfilesWithConflictingProfilesAndValue() {
resolveActiveProfiles(ConflictingProfilesAndValueTest.class);
}
/**
* @since 4.0
*/
@Test(expected = IllegalStateException.class)
public void resolveActiveProfilesWithResolverWithoutDefaultConstructor() {
resolveActiveProfiles(NoDefaultConstructorActiveProfilesResolverTest.class);
}
/**
* @since 4.0
*/
@Test(expected = IllegalStateException.class)
public void resolveActiveProfilesWithResolverThatReturnsNull() {
resolveActiveProfiles(NullActiveProfilesResolverTest.class);
}
// -------------------------------------------------------------------------
// --- General Purpose Classes and Config ----------------------------------
private static class Enigma {
}
@ -677,6 +764,80 @@ public class ContextLoaderUtilsTests { @@ -677,6 +764,80 @@ public class ContextLoaderUtilsTests {
private static class Animals extends LocationsBar {
}
// --- ActiveProfilesResolver ----------------------------------------------
public static class FooActiveProfilesResolver implements ActiveProfilesResolver {
@Override
public String[] resolve(Class<?> testClass) {
return new String[] { "foo" };
}
}
public static class BarActiveProfilesResolver implements ActiveProfilesResolver {
@Override
public String[] resolve(Class<?> testClass) {
return new String[] { "bar" };
}
}
public static class NullActiveProfilesResolver implements ActiveProfilesResolver {
@Override
public String[] resolve(Class<?> testClass) {
return null;
}
}
public static class NoDefaultConstructorActiveProfilesResolver implements ActiveProfilesResolver {
public NoDefaultConstructorActiveProfilesResolver(Object agument) {
}
@Override
public String[] resolve(Class<?> testClass) {
return null;
}
}
@ActiveProfiles(resolver = NullActiveProfilesResolver.class)
private static class NullActiveProfilesResolverTest {
}
@ActiveProfiles(resolver = NoDefaultConstructorActiveProfilesResolver.class)
private static class NoDefaultConstructorActiveProfilesResolverTest {
}
@ActiveProfiles(resolver = FooActiveProfilesResolver.class)
private static class FooActiveProfilesResolverTest {
}
private static class InheritedFooActiveProfilesResolverTest extends FooActiveProfilesResolverTest {
}
@ActiveProfiles(resolver = BarActiveProfilesResolver.class)
private static class MergedInheritedFooActiveProfilesResolverTest extends InheritedFooActiveProfilesResolverTest {
}
@ActiveProfiles(resolver = BarActiveProfilesResolver.class, inheritProfiles = false)
private static class OverridenInheritedFooActiveProfilesResolverTest extends InheritedFooActiveProfilesResolverTest {
}
@ActiveProfiles(resolver = BarActiveProfilesResolver.class, profiles = "conflict")
private static class ConflictingResolverAndProfilesTest {
}
@ActiveProfiles(resolver = BarActiveProfilesResolver.class, value = "conflict")
private static class ConflictingResolverAndValueTest {
}
@ActiveProfiles(profiles = "conflict", value = "conflict")
private static class ConflictingProfilesAndValueTest {
}
// --- ApplicationContextInitializer ---------------------------------------
private static class FooInitializer implements ApplicationContextInitializer<GenericApplicationContext> {
@Override
@ -707,6 +868,8 @@ public class ContextLoaderUtilsTests { @@ -707,6 +868,8 @@ public class ContextLoaderUtilsTests {
private static class OverriddenInitializersAndClassesBar extends InitializersFoo {
}
// --- @ContextHierarchy ---------------------------------------------------
@ContextConfiguration("foo.xml")
@ContextHierarchy(@ContextConfiguration("bar.xml"))
private static class SingleTestClassWithContextConfigurationAndContextHierarchy {

4
spring-test/src/test/java/org/springframework/test/context/junit4/SpringJUnit4TestSuite.java

@ -37,7 +37,9 @@ import org.springframework.test.context.junit4.annotation.ExplicitConfigClassesI @@ -37,7 +37,9 @@ import org.springframework.test.context.junit4.annotation.ExplicitConfigClassesI
import org.springframework.test.context.junit4.orm.HibernateSessionFlushingTests;
import org.springframework.test.context.junit4.profile.annotation.DefaultProfileAnnotationConfigTests;
import org.springframework.test.context.junit4.profile.annotation.DevProfileAnnotationConfigTests;
import org.springframework.test.context.junit4.profile.annotation.DevProfileResolverAnnotationConfigTests;
import org.springframework.test.context.junit4.profile.xml.DefaultProfileXmlConfigTests;
import org.springframework.test.context.junit4.profile.xml.DevProfileResolverXmlConfigTests;
import org.springframework.test.context.junit4.profile.xml.DevProfileXmlConfigTests;
/**
@ -77,8 +79,10 @@ StandardJUnit4FeaturesTests.class,// @@ -77,8 +79,10 @@ StandardJUnit4FeaturesTests.class,//
DefaultLoaderBeanOverridingExplicitConfigClassesInheritedTests.class,//
DefaultProfileAnnotationConfigTests.class,//
DevProfileAnnotationConfigTests.class,//
DevProfileResolverAnnotationConfigTests.class,//
DefaultProfileXmlConfigTests.class,//
DevProfileXmlConfigTests.class,//
DevProfileResolverXmlConfigTests.class,//
ExpectedExceptionSpringRunnerTests.class,//
TimedSpringRunnerTests.class,//
RepeatedSpringRunnerTests.class,//

34
spring-test/src/test/java/org/springframework/test/context/junit4/profile/annotation/DevProfileResolverAnnotationConfigTests.java

@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
/*
* 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.junit4.profile.annotation;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ActiveProfilesResolver;
/**
* @author Michail Nikolaev
* @since 4.0
*/
@ActiveProfiles(resolver = DevProfileResolverAnnotationConfigTests.class, inheritProfiles = false)
public class DevProfileResolverAnnotationConfigTests extends DevProfileAnnotationConfigTests implements
ActiveProfilesResolver {
@Override
public String[] resolve(Class<?> testClass) {
return new String[] { "dev" };
}
}

5
spring-test/src/test/java/org/springframework/test/context/junit4/profile/annotation/ProfileAnnotationConfigTestSuite.java

@ -1,5 +1,5 @@ @@ -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.
@ -31,7 +31,8 @@ import org.junit.runners.Suite.SuiteClasses; @@ -31,7 +31,8 @@ import org.junit.runners.Suite.SuiteClasses;
// Note: the following 'multi-line' layout is for enhanced code readability.
@SuiteClasses({//
DefaultProfileAnnotationConfigTests.class,//
DevProfileAnnotationConfigTests.class //
DevProfileAnnotationConfigTests.class,//
DevProfileResolverAnnotationConfigTests.class //
})
public class ProfileAnnotationConfigTestSuite {
}

34
spring-test/src/test/java/org/springframework/test/context/junit4/profile/importresource/DevProfileResolverAnnotationConfigTests.java

@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
/*
* 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.junit4.profile.importresource;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ActiveProfilesResolver;
/**
* @author Michail Nikolaev
* @since 4.0
*/
@ActiveProfiles(resolver = DevProfileResolverAnnotationConfigTests.class, inheritProfiles = false)
public class DevProfileResolverAnnotationConfigTests extends DevProfileAnnotationConfigTests implements
ActiveProfilesResolver {
@Override
public String[] resolve(Class<?> testClass) {
return new String[] { "dev" };
}
}

31
spring-test/src/test/java/org/springframework/test/context/junit4/profile/resolver/ClassNameActiveProfilesResolver.java

@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
/*
* 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.junit4.profile.resolver;
import org.springframework.test.context.ActiveProfilesResolver;
/**
* @author Michail Nikolaev
* @since 4.0
*/
public class ClassNameActiveProfilesResolver implements ActiveProfilesResolver {
@Override
public String[] resolve(Class<?> testClass) {
return new String[] { testClass.getSimpleName().toLowerCase() };
}
}

57
spring-test/src/test/java/org/springframework/test/context/junit4/profile/resolver/ClassNameActiveProfilesResolverTest.java

@ -0,0 +1,57 @@ @@ -0,0 +1,57 @@
/*
* 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.junit4.profile.resolver;
import java.util.Arrays;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.junit.Assert.*;
/**
* @author Michail Nikolaev
* @since 4.0
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@ActiveProfiles(resolver = ClassNameActiveProfilesResolver.class)
public class ClassNameActiveProfilesResolverTest {
@Configuration
static class Config {
}
@Autowired
private ApplicationContext applicationContext;
@Test
public void test() {
assertTrue(Arrays.asList(applicationContext.getEnvironment().getActiveProfiles()).contains(
getClass().getSimpleName().toLowerCase()));
}
}

34
spring-test/src/test/java/org/springframework/test/context/junit4/profile/xml/DevProfileResolverXmlConfigTests.java

@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
/*
* 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.junit4.profile.xml;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ActiveProfilesResolver;
/**
* @author Michail Nikolaev
* @since 4.0
*/
@ActiveProfiles(resolver = DevProfileResolverXmlConfigTests.class, inheritProfiles = false)
public class DevProfileResolverXmlConfigTests extends DevProfileXmlConfigTests implements ActiveProfilesResolver {
@Override
public String[] resolve(Class<?> testClass) {
return new String[] { "dev" };
}
}

5
spring-test/src/test/java/org/springframework/test/context/junit4/profile/xml/ProfileXmlConfigTestSuite.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 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.
@ -31,7 +31,8 @@ import org.junit.runners.Suite.SuiteClasses; @@ -31,7 +31,8 @@ import org.junit.runners.Suite.SuiteClasses;
// Note: the following 'multi-line' layout is for enhanced code readability.
@SuiteClasses({//
DefaultProfileXmlConfigTests.class,//
DevProfileXmlConfigTests.class //
DevProfileXmlConfigTests.class,//
DevProfileResolverXmlConfigTests.class //
})
public class ProfileXmlConfigTestSuite {
}

318
src/reference/docbook/testing.xml

@ -197,7 +197,6 @@ @@ -197,7 +197,6 @@
TestContext framework is agnostic of the actual testing framework in use,
thus allowing instrumentation of tests in various environments including
JUnit, TestNG, and so on.</para>
</section>
<section xml:id="integration-testing-goals">
@ -444,13 +443,13 @@ @@ -444,13 +443,13 @@
<programlisting language="java"><emphasis role="bold">@ContextConfiguration</emphasis>("/test-config.xml")
public class XmlApplicationContextTests {
<lineannotation>// class body...</lineannotation>
// class body...
}</programlisting>
<programlisting language="java"><emphasis role="bold">@ContextConfiguration</emphasis>(<emphasis
role="bold">classes</emphasis> = TestConfig.class)
public class ConfigClassApplicationContextTests {
<lineannotation>// class body...</lineannotation>
// class body...
}</programlisting>
<para>As an alternative or in addition to declaring resource
@ -462,7 +461,7 @@ public class ConfigClassApplicationContextTests { @@ -462,7 +461,7 @@ public class ConfigClassApplicationContextTests {
<programlisting language="java"><emphasis role="bold">@ContextConfiguration</emphasis>(<emphasis
role="bold">initializers</emphasis> = CustomContextIntializer.class)
public class ContextInitializerTests {
<lineannotation>// class body...</lineannotation>
// class body...
}</programlisting>
<para><interfacename>@ContextConfiguration</interfacename> may
@ -477,7 +476,7 @@ public class ContextInitializerTests { @@ -477,7 +476,7 @@ public class ContextInitializerTests {
role="bold">locations</emphasis> = "/test-context.xml", <emphasis
role="bold">loader</emphasis> = CustomContextLoader.class)
public class CustomLoaderXmlApplicationContextTests {
<lineannotation>// class body...</lineannotation>
// class body...
}</programlisting>
<note>
@ -514,7 +513,7 @@ public class CustomLoaderXmlApplicationContextTests { @@ -514,7 +513,7 @@ public class CustomLoaderXmlApplicationContextTests {
<programlisting language="java">@ContextConfiguration
<emphasis role="bold">@WebAppConfiguration</emphasis>
public class WebAppTests {
<lineannotation>// class body...</lineannotation>
// class body...
}</programlisting>
<para>To override the default, specify a different base resource
@ -527,7 +526,7 @@ public class WebAppTests { @@ -527,7 +526,7 @@ public class WebAppTests {
<programlisting language="java">@ContextConfiguration
<emphasis role="bold">@WebAppConfiguration("classpath:test-web-resources")</emphasis>
public class WebAppTests {
<lineannotation>// class body...</lineannotation>
// class body...
}</programlisting>
<para>Note that <interfacename>@WebAppConfiguration</interfacename>
@ -559,7 +558,7 @@ public class WebAppTests { @@ -559,7 +558,7 @@ public class WebAppTests {
@ContextConfiguration("/child-config.xml")
})
public class ContextHierarchyTests {
<lineannotation>// class body...</lineannotation>
// class body...
}</programlisting>
<programlisting language="java">@WebAppConfiguration
@ -568,7 +567,7 @@ public class ContextHierarchyTests { @@ -568,7 +567,7 @@ public class ContextHierarchyTests {
@ContextConfiguration(classes = WebConfig.class)
})
public class WebIntegrationTests {
<lineannotation>// class body...</lineannotation>
// class body...
}</programlisting>
<para>If you need to merge or override the configuration for a given
@ -594,19 +593,24 @@ public class WebIntegrationTests { @@ -594,19 +593,24 @@ public class WebIntegrationTests {
<programlisting language="java">@ContextConfiguration
<emphasis role="bold">@ActiveProfiles</emphasis>("dev")
public class DeveloperTests {
<lineannotation>// class body...</lineannotation>
// class body...
}</programlisting>
<programlisting language="java">@ContextConfiguration
<emphasis role="bold">@ActiveProfiles</emphasis>({"dev", "integration"})
public class DeveloperIntegrationTests {
<lineannotation>// class body...</lineannotation>
// class body...
}</programlisting>
<note>
<para><interfacename>@ActiveProfiles</interfacename> provides
support for <emphasis>inheriting</emphasis> active bean definition
profiles declared by superclasses by default.</para>
profiles declared by superclasses by default. It is also possible
to resolve active bean definition profiles programmatically by
implementing a custom
<interfacename>ActiveProfilesResolver</interfacename> and
registering it via the <varname>resolver</varname> attribute of
<interfacename>@ActiveProfiles</interfacename>.</para>
</note>
<para>See <xref linkend="testcontext-ctx-management-env-profiles"/>
@ -649,19 +653,20 @@ public class DeveloperIntegrationTests { @@ -649,19 +653,20 @@ public class DeveloperIntegrationTests {
<programlisting language="java"><emphasis role="bold">@DirtiesContext</emphasis>
public class ContextDirtyingTests {
<lineannotation>// some tests that result in the Spring container being dirtied</lineannotation>
// some tests that result in the Spring container being dirtied
}</programlisting>
</listitem>
<listitem>
<para>After each test method in the current test class, when
declared on a class with class mode set to
<literal>AFTER_EACH_TEST_METHOD.</literal><programlisting
language="java"><emphasis role="bold">@DirtiesContext</emphasis>(<emphasis
role="bold">classMode</emphasis> = ClassMode.AFTER_EACH_TEST_METHOD)
<literal>AFTER_EACH_TEST_METHOD.</literal></para>
<programlisting language="java"><emphasis role="bold">@DirtiesContext</emphasis>(<emphasis
role="bold">classMode</emphasis> = ClassMode.AFTER_EACH_TEST_METHOD)
public class ContextDirtyingTests {
<lineannotation>// some tests that result in the Spring container being dirtied</lineannotation>
}</programlisting></para>
// some tests that result in the Spring container being dirtied
}</programlisting>
</listitem>
<listitem>
@ -670,7 +675,7 @@ public class ContextDirtyingTests { @@ -670,7 +675,7 @@ public class ContextDirtyingTests {
<programlisting language="java"><emphasis role="bold">@DirtiesContext</emphasis>
@Test
public void testProcessWhichDirtiesAppCtx() {
<lineannotation>// some logic that results in the Spring container being dirtied</lineannotation>
// some logic that results in the Spring container being dirtied
}</programlisting>
</listitem>
</itemizedlist>
@ -696,7 +701,7 @@ public void testProcessWhichDirtiesAppCtx() { @@ -696,7 +701,7 @@ public void testProcessWhichDirtiesAppCtx() {
@ContextConfiguration("/child-config.xml")
})
public class BaseTests {
<lineannotation>// class body...</lineannotation>
// class body...
}
public class ExtendedTests extends BaseTests {
@ -704,7 +709,7 @@ public class ExtendedTests extends BaseTests { @@ -704,7 +709,7 @@ public class ExtendedTests extends BaseTests {
@Test
@DirtiesContext(<emphasis role="bold">hierarchyMode = HierarchyMode.CURRENT_LEVEL</emphasis>)
public void test() {
<lineannotation>// some logic that results in the child context being dirtied</lineannotation>
// some logic that results in the child context being dirtied
}
}</programlisting>
@ -729,7 +734,7 @@ public class ExtendedTests extends BaseTests { @@ -729,7 +734,7 @@ public class ExtendedTests extends BaseTests {
<programlisting language="java">@ContextConfiguration
<emphasis role="bold">@TestExecutionListeners</emphasis>({CustomTestExecutionListener.class, AnotherTestExecutionListener.class})
public class CustomTestExecutionListenerTests {
<lineannotation>// class body...</lineannotation>
// class body...
}</programlisting>
<para><interfacename>@TestExecutionListeners</interfacename>
@ -761,7 +766,7 @@ public class CustomTestExecutionListenerTests { @@ -761,7 +766,7 @@ public class CustomTestExecutionListenerTests {
<emphasis role="bold">@TransactionConfiguration</emphasis>(<emphasis role="bold">transactionManager</emphasis> = "txMgr", <emphasis
role="bold">defaultRollback</emphasis> = false)
public class CustomConfiguredTransactionalTests {
<lineannotation>// class body...</lineannotation>
// class body...
}</programlisting>
<note>
@ -793,7 +798,7 @@ public class CustomConfiguredTransactionalTests { @@ -793,7 +798,7 @@ public class CustomConfiguredTransactionalTests {
<programlisting language="java"><emphasis role="bold">@Rollback</emphasis>(false)
@Test
public void testProcessWithoutRollback() {
<lineannotation>// ...</lineannotation>
// ...
}</programlisting>
</listitem>
@ -809,7 +814,7 @@ public void testProcessWithoutRollback() { @@ -809,7 +814,7 @@ public void testProcessWithoutRollback() {
<programlisting language="java"><emphasis role="bold">@BeforeTransaction
</emphasis>public void beforeTransaction() {
<lineannotation>// logic to be executed before a transaction is started</lineannotation>
// logic to be executed before a transaction is started
}</programlisting>
</listitem>
@ -825,7 +830,7 @@ public void testProcessWithoutRollback() { @@ -825,7 +830,7 @@ public void testProcessWithoutRollback() {
<programlisting language="java"><emphasis role="bold">@AfterTransaction
</emphasis>public void afterTransaction() {
<lineannotation>// logic to be executed after a transaction has ended</lineannotation>
// logic to be executed after a transaction has ended
}</programlisting>
</listitem>
</itemizedlist>
@ -944,7 +949,7 @@ public void testProcessWithoutRollback() { @@ -944,7 +949,7 @@ public void testProcessWithoutRollback() {
role="bold">name</emphasis>="java.vendor", <emphasis role="bold">value</emphasis>="Sun Microsystems Inc.")
@Test
public void testProcessWhichRunsOnlyOnSunJvm() {
<lineannotation>// some logic that should run only on Java VMs from Sun Microsystems</lineannotation>
// some logic that should run only on Java VMs from Sun Microsystems
}</programlisting>
<para>Alternatively, you can configure
@ -957,7 +962,7 @@ public void testProcessWhichRunsOnlyOnSunJvm() { @@ -957,7 +962,7 @@ public void testProcessWhichRunsOnlyOnSunJvm() {
role="bold">name</emphasis>="test-groups", <emphasis role="bold">values</emphasis>={"unit-tests", "integration-tests"})
@Test
public void testProcessWhichRunsForUnitOrIntegrationTestGroups() {
<lineannotation>// some logic that should run only for unit and integration test groups</lineannotation>
// some logic that should run only for unit and integration test groups
}</programlisting>
</listitem>
@ -977,7 +982,7 @@ public void testProcessWhichRunsForUnitOrIntegrationTestGroups() { @@ -977,7 +982,7 @@ public void testProcessWhichRunsForUnitOrIntegrationTestGroups() {
<programlisting language="java"><emphasis role="bold">@ProfileValueSourceConfiguration</emphasis>(CustomProfileValueSource.class)
public class CustomProfileValueSourceTests {
<lineannotation>// class body...</lineannotation>
// class body...
}</programlisting>
</listitem>
@ -997,7 +1002,7 @@ public class CustomProfileValueSourceTests { @@ -997,7 +1002,7 @@ public class CustomProfileValueSourceTests {
<programlisting language="java"><emphasis role="bold">@Timed</emphasis>(millis=1000)
public void testProcessWithOneSecondTimeout() {
<lineannotation>// some logic that should not take longer than 1 second to execute</lineannotation>
// some logic that should not take longer than 1 second to execute
}</programlisting>
<para>Spring's <interfacename>@Timed</interfacename> annotation has
@ -1030,7 +1035,7 @@ public void testProcessWithOneSecondTimeout() { @@ -1030,7 +1035,7 @@ public void testProcessWithOneSecondTimeout() {
<programlisting language="java"><emphasis role="bold">@Repeat</emphasis>(10)
@Test
public void testProcessRepeatedly() {
<lineannotation>// ...</lineannotation>
// ...
}</programlisting>
</listitem>
</itemizedlist>
@ -1286,7 +1291,7 @@ public class MyTest { @@ -1286,7 +1291,7 @@ public class MyTest {
<emphasis role="bold">@Autowired</emphasis>
private ApplicationContext applicationContext;
<lineannotation>// class body...</lineannotation>
// class body...
}</programlisting>
<para>Similarly, if your test is configured to load a
@ -1301,7 +1306,7 @@ public class MyWebAppTest { @@ -1301,7 +1306,7 @@ public class MyWebAppTest {
<emphasis role="bold">@Autowired</emphasis>
private WebApplicationContext wac;
<lineannotation>// class body...</lineannotation>
// class body...
}</programlisting>
<para>Dependency injection via
@ -1355,11 +1360,11 @@ public class MyWebAppTest { @@ -1355,11 +1360,11 @@ public class MyWebAppTest {
is</emphasis>.</para>
<programlisting language="java">@RunWith(SpringJUnit4ClassRunner.class)
<lineannotation>// ApplicationContext will be loaded from "/app-config.xml" and
// "/test-config.xml" in the root of the classpath</lineannotation>
// ApplicationContext will be loaded from "/app-config.xml" and
// "/test-config.xml" in the root of the classpath
<emphasis role="bold">@ContextConfiguration(locations={"/app-config.xml", "/test-config.xml"})</emphasis>
public class MyTest {
<lineannotation>// class body...</lineannotation>
// class body...
}</programlisting>
<para><interfacename>@ContextConfiguration</interfacename> supports an
@ -1374,7 +1379,7 @@ public class MyTest { @@ -1374,7 +1379,7 @@ public class MyTest {
<programlisting language="java">@RunWith(SpringJUnit4ClassRunner.class)
<emphasis role="bold">@ContextConfiguration({"/app-config.xml", "/test-config.xml"})</emphasis>
public class MyTest {
<lineannotation>// class body...</lineannotation>
// class body...
}</programlisting>
<para>If you omit both the <varname>locations</varname> and
@ -1391,11 +1396,11 @@ public class MyTest { @@ -1391,11 +1396,11 @@ public class MyTest {
<programlisting language="java">package com.example;
@RunWith(SpringJUnit4ClassRunner.class)
<lineannotation>// ApplicationContext will be loaded from
// "classpath:/com/example/MyTest-context.xml"</lineannotation>
// ApplicationContext will be loaded from
// "classpath:/com/example/MyTest-context.xml"
<emphasis role="bold">@ContextConfiguration</emphasis>
public class MyTest {
<lineannotation>// class body...</lineannotation>
// class body...
}</programlisting>
</section>
@ -1410,10 +1415,10 @@ public class MyTest { @@ -1410,10 +1415,10 @@ public class MyTest {
references to annotated classes.</para>
<programlisting language="java">@RunWith(SpringJUnit4ClassRunner.class)
<lineannotation>// ApplicationContext will be loaded from AppConfig and TestConfig</lineannotation>
// ApplicationContext will be loaded from AppConfig and TestConfig
<emphasis role="bold">@ContextConfiguration(classes = {AppConfig.class, TestConfig.class})</emphasis>
public class MyTest {
<lineannotation>// class body...</lineannotation>
// class body...
}</programlisting>
<para>If you omit the <varname>classes</varname> attribute from the
@ -1433,19 +1438,19 @@ public class MyTest { @@ -1433,19 +1438,19 @@ public class MyTest {
configuration class if desired.</para>
<programlisting language="java">@RunWith(SpringJUnit4ClassRunner.class)
<lineannotation>// ApplicationContext will be loaded from the
// static inner Config class</lineannotation>
// ApplicationContext will be loaded from the
// static inner Config class
<emphasis role="bold">@ContextConfiguration</emphasis>
public class OrderServiceTest {
@Configuration
static class Config {
<lineannotation>// this bean will be injected into the OrderServiceTest class</lineannotation>
// this bean will be injected into the OrderServiceTest class
@Bean
public OrderService orderService() {
OrderService orderService = new OrderServiceImpl();
<lineannotation>// set properties, etc.</lineannotation>
// set properties, etc.
return orderService;
}
}
@ -1455,7 +1460,7 @@ public class OrderServiceTest { @@ -1455,7 +1460,7 @@ public class OrderServiceTest {
@Test
public void testOrderService() {
<lineannotation>// test the orderService</lineannotation>
// test the orderService
}
}</programlisting>
@ -1520,13 +1525,13 @@ public class OrderServiceTest { @@ -1520,13 +1525,13 @@ public class OrderServiceTest {
Spring's <interfacename>@Order</interfacename> annotation.</para>
<programlisting language="java">@RunWith(SpringJUnit4ClassRunner.class)
<lineannotation>// ApplicationContext will be loaded from TestConfig
</lineannotation><lineannotation>// and initialized by TestAppCtxInitializer</lineannotation>
// ApplicationContext will be loaded from TestConfig
// and initialized by TestAppCtxInitializer
<emphasis role="bold">@ContextConfiguration(
classes = TestConfig.class,
initializers = TestAppCtxInitializer.class)</emphasis>
public class MyTest {
<lineannotation>// class body...</lineannotation>
// class body...
}</programlisting>
<para>It is also possible to omit the declaration of XML configuration
@ -1539,11 +1544,11 @@ public class MyTest { @@ -1539,11 +1544,11 @@ public class MyTest {
or configuration classes.</para>
<programlisting language="java">@RunWith(SpringJUnit4ClassRunner.class)
<lineannotation>// ApplicationContext will be initialized by EntireAppInitializer
</lineannotation><lineannotation>// which presumably registers beans in the context</lineannotation>
// ApplicationContext will be initialized by EntireAppInitializer
// which presumably registers beans in the context
<emphasis role="bold">@ContextConfiguration(initializers = EntireAppInitializer.class)</emphasis>
public class MyTest {
<lineannotation>// class body...</lineannotation>
// class body...
}</programlisting>
</section>
@ -1585,18 +1590,18 @@ public class MyTest { @@ -1585,18 +1590,18 @@ public class MyTest {
<emphasis>"base-config.xml"</emphasis>.</para>
<programlisting language="java">@RunWith(SpringJUnit4ClassRunner.class)
<lineannotation>// ApplicationContext will be loaded from "/base-config.xml"
// in the root of the classpath</lineannotation>
// ApplicationContext will be loaded from "/base-config.xml"
// in the root of the classpath
<emphasis role="bold">@ContextConfiguration("/base-config.xml")</emphasis>
public class BaseTest {
<lineannotation>// class body...</lineannotation>
// class body...
}
<lineannotation>// ApplicationContext will be loaded from "/base-config.xml" and
// "/extended-config.xml" </lineannotation><lineannotation>in the root of the classpath</lineannotation>
// ApplicationContext will be loaded from "/base-config.xml" and
// "/extended-config.xml" in the root of the classpath
<emphasis role="bold">@ContextConfiguration("/extended-config.xml")</emphasis>
public class ExtendedTest extends BaseTest {
<lineannotation>// class body...</lineannotation>
// class body...
}</programlisting>
<para>Similarly, in the following example that uses annotated classes,
@ -1609,16 +1614,16 @@ public class ExtendedTest extends BaseTest { @@ -1609,16 +1614,16 @@ public class ExtendedTest extends BaseTest {
<classname>BaseConfig</classname>.</para>
<programlisting language="java">@RunWith(SpringJUnit4ClassRunner.class)
<lineannotation>// ApplicationContext will be loaded from BaseConfig</lineannotation>
// ApplicationContext will be loaded from BaseConfig
<emphasis role="bold">@ContextConfiguration(classes = BaseConfig.class)</emphasis>
public class BaseTest {
<lineannotation>// class body...</lineannotation>
// class body...
}
<lineannotation>// ApplicationContext will be loaded from BaseConfig and ExtendedConfig</lineannotation>
// ApplicationContext will be loaded from BaseConfig and ExtendedConfig
<emphasis role="bold">@ContextConfiguration(classes = ExtendedConfig.class)</emphasis>
public class ExtendedTest extends BaseTest {
<lineannotation>// class body...</lineannotation>
// class body...
}</programlisting>
<para>In the following example that uses context initializers, the
@ -1632,17 +1637,17 @@ public class ExtendedTest extends BaseTest { @@ -1632,17 +1637,17 @@ public class ExtendedTest extends BaseTest {
Spring's <interfacename>@Order</interfacename> annotation.</para>
<programlisting language="java">@RunWith(SpringJUnit4ClassRunner.class)
<lineannotation>// ApplicationContext will be initialized by BaseInitializer</lineannotation>
// ApplicationContext will be initialized by BaseInitializer
<emphasis role="bold">@ContextConfiguration(initializers=BaseInitializer.class)</emphasis>
public class BaseTest {
<lineannotation>// class body...</lineannotation>
// class body...
}
<lineannotation>// ApplicationContext will be initialized by BaseInitializer
// and ExtendedInitializer</lineannotation>
// ApplicationContext will be initialized by BaseInitializer
// and ExtendedInitializer
<emphasis role="bold">@ContextConfiguration(initializers=ExtendedInitializer.class)</emphasis>
public class ExtendedTest extends BaseTest {
<lineannotation>// class body...</lineannotation>
// class body...
}</programlisting>
</section>
@ -1814,7 +1819,7 @@ public class TransferServiceTest { @@ -1814,7 +1819,7 @@ public class TransferServiceTest {
@Test
public void testTransferService() {
// test the transferService
// test the transferService
}
}</programlisting>
@ -1849,7 +1854,113 @@ public class TransferServiceTest { @@ -1849,7 +1854,113 @@ public class TransferServiceTest {
<interfacename>@ContextConfiguration </interfacename>annotation. The
body of the test class itself remains completely unchanged.</para>
<!-- TODO Consider documenting inheritance for active profiles. -->
<para>It is often the case that a single set of profiles is used
across multiple test classes within a given project. Thus, to avoid
duplicate declarations of the
<interfacename>@ActiveProfiles</interfacename> annotation it is
possible to declare <interfacename>@ActiveProfiles</interfacename>
once on a base class, and subclasses will automatically inherit the
<interfacename>@ActiveProfiles</interfacename> configuration from the
base class. In the following example, the declaration of
<interfacename>@ActiveProfiles</interfacename> (as well as other
annotations) has been moved to an abstract superclass,
<classname>AbstractIntegrationTest</classname>.</para>
<programlisting language="java">package com.bank.service;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
classes = {
TransferServiceConfig.class,
StandaloneDataConfig.class,
JndiDataConfig.class})
@ActiveProfiles("dev")
public abstract class AbstractIntegrationTest {
}</programlisting>
<programlisting language="java">package com.bank.service;
// "dev" profile inherited from superclass
public class TransferServiceTest extends AbstractIntegrationTest {
@Autowired
private TransferService transferService;
@Test
public void testTransferService() {
// test the transferService
}
}</programlisting>
<para><interfacename>@ActiveProfiles</interfacename> also supports an
<methodname>inheritProfiles</methodname> attribute that can be used to
disable the inheritance of active profiles.</para>
<programlisting language="java">package com.bank.service;
// "dev" profile overridden with "production"
@ActiveProfiles(profiles = "production", inheritProfiles = false)
public class ProductionTransferServiceTest extends AbstractIntegrationTest {
// test body
}</programlisting>
<para>Furthermore, it is sometimes necessary to resolve active
profiles for tests <emphasis>programmatically</emphasis> instead of
declaratively — for example, based on:</para>
<itemizedlist>
<listitem>
<para>the current operating system</para>
</listitem>
<listitem>
<para>whether tests are being executed on a continuous integration
build server</para>
</listitem>
<listitem>
<para>the presence of certain environment variables</para>
</listitem>
<listitem>
<para>the presence of custom class-level annotations</para>
</listitem>
<listitem>
<para>etc.</para>
</listitem>
</itemizedlist>
<para>To resolve active bean definition profiles programmatically,
simply implement a custom
<interfacename>ActiveProfilesResolver</interfacename> and register it
via the <varname>resolver</varname> attribute of
<interfacename>@ActiveProfiles</interfacename>. The following example
demonstrates how to implement and register a custom
<classname>OperatingSystemActiveProfilesResolver</classname>. For
further information, refer to the respective Javadoc.</para>
<programlisting language="java">package com.bank.service;
// "dev" profile overridden programmatically via a custom resolver
@ActiveProfiles(
resolver = OperatingSystemActiveProfilesResolver.class,
inheritProfiles = false)
public class TransferServiceTest extends AbstractIntegrationTest {
// test body
}</programlisting>
<programlisting language="java">package com.bank.service.test;
public class OperatingSystemActiveProfilesResolver implements ActiveProfilesResolver {
@Override
String[] resolve(Class&lt;?&gt; testClass) {
String profile = ...;
// determine the value of profile based on the operating system
return new String[] {profile};
}
}</programlisting>
</section>
<section xml:id="testcontext-ctx-management-web">
@ -2416,11 +2527,11 @@ public class ExtendedTests extends BaseTests {}</programlisting> @@ -2416,11 +2527,11 @@ public class ExtendedTests extends BaseTests {}</programlisting>
injection.</para>
<programlisting language="java">@RunWith(SpringJUnit4ClassRunner.class)
<lineannotation>// specifies the Spring configuration to load for this test fixture</lineannotation>
// specifies the Spring configuration to load for this test fixture
<emphasis role="bold">@ContextConfiguration("repository-config.xml")</emphasis>
public class HibernateTitleRepositoryTests {
<lineannotation>// this instance will be dependency injected by type</lineannotation>
// this instance will be dependency injected by type
<emphasis role="bold">@Autowired</emphasis>
private HibernateTitleRepository titleRepository;
@ -2436,11 +2547,11 @@ public class HibernateTitleRepositoryTests { @@ -2436,11 +2547,11 @@ public class HibernateTitleRepositoryTests {
below.</para>
<programlisting language="java">@RunWith(SpringJUnit4ClassRunner.class)
<lineannotation>// specifies the Spring configuration to load for this test fixture</lineannotation>
// specifies the Spring configuration to load for this test fixture
<emphasis role="bold">@ContextConfiguration("repository-config.xml")</emphasis>
public class HibernateTitleRepositoryTests {
<lineannotation>// this instance will be dependency injected by type</lineannotation>
// this instance will be dependency injected by type
private HibernateTitleRepository titleRepository;
<emphasis role="bold">@Autowired</emphasis>
@ -2490,7 +2601,7 @@ public class HibernateTitleRepositoryTests { @@ -2490,7 +2601,7 @@ public class HibernateTitleRepositoryTests {
specific target bean as follows, but make sure to delegate to the
overridden method in the superclass as well.</para>
<programlisting language="java"><lineannotation>// ...</lineannotation>
<programlisting language="java">// ...
@Autowired
@Override
@ -2498,7 +2609,7 @@ public class HibernateTitleRepositoryTests { @@ -2498,7 +2609,7 @@ public class HibernateTitleRepositoryTests {
<emphasis role="bold">super</emphasis>.setDataSource(dataSource);
}
<lineannotation>// ...</lineannotation></programlisting>
// ...</programlisting>
<para>The specified qualifier value indicates the specific
<interfacename>DataSource</interfacename> bean to inject, narrowing
@ -2749,29 +2860,29 @@ public class FictitiousTransactionalTest { @@ -2749,29 +2860,29 @@ public class FictitiousTransactionalTest {
<emphasis role="bold">@BeforeTransaction</emphasis>
public void verifyInitialDatabaseState() {
<lineannotation>// logic to verify the initial state before a transaction is started</lineannotation>
// logic to verify the initial state before a transaction is started
}
@Before
public void setUpTestDataWithinTransaction() {
<lineannotation>// set up test data within the transaction</lineannotation>
// set up test data within the transaction
}
@Test
<lineannotation>// overrides the class-level defaultRollback setting</lineannotation>
// overrides the class-level defaultRollback setting
<emphasis role="bold">@Rollback(true)</emphasis>
public void modifyDatabaseWithinTransaction() {
<lineannotation>// logic which uses the test data and modifies database state</lineannotation>
// logic which uses the test data and modifies database state
}
@After
public void tearDownWithinTransaction() {
<lineannotation>// execute "tear down" logic within the transaction</lineannotation>
// execute "tear down" logic within the transaction
}
<emphasis role="bold">@AfterTransaction</emphasis>
public void verifyFinalDatabaseState() {
<lineannotation>// logic to verify the final state after transaction has rolled back</lineannotation>
// logic to verify the final state after transaction has rolled back
}
}</programlisting>
@ -2793,7 +2904,7 @@ public class FictitiousTransactionalTest { @@ -2793,7 +2904,7 @@ public class FictitiousTransactionalTest {
frameworks that maintain an in-memory <emphasis>unit of
work</emphasis>.</para>
<programlisting language="java"><lineannotation>// ...</lineannotation>
<programlisting language="java">// ...
@Autowired
private SessionFactory sessionFactory;
@ -2812,7 +2923,7 @@ public void updateWithSessionFlush() { @@ -2812,7 +2923,7 @@ public void updateWithSessionFlush() {
sessionFactory.getCurrentSession().flush();
}
<lineannotation>// ...</lineannotation></programlisting>
// ...</programlisting>
</note>
</section>
@ -2922,7 +3033,7 @@ public class SimpleTest { @@ -2922,7 +3033,7 @@ public class SimpleTest {
@Test
public void testMethod() {
<lineannotation>// execute test logic...</lineannotation>
// execute test logic...
}
}</programlisting>
</section>
@ -3226,8 +3337,7 @@ public class MyWebTests { @@ -3226,8 +3337,7 @@ public class MyWebTests {
<programlisting language="xml">&lt;bean id="accountService" class="org.mockito.Mockito" factory-method="mock"&gt;
&lt;constructor-arg value="org.example.AccountService"/&gt;
&lt;/bean&gt;
</programlisting>
&lt;/bean&gt;</programlisting>
<para>Then you can inject the mock service into the test in order set
up and verify expectations:</para>
@ -3274,26 +3384,22 @@ public class AccountTests { @@ -3274,26 +3384,22 @@ public class AccountTests {
additional builder-style methods corresponding to properties of
<classname>MockHttpServletRequest</classname>. For example:</para>
<programlisting language="java">mockMvc.perform(post("/hotels/{id}", 42).accept(MediaType.APPLICATION_JSON));
</programlisting>
<programlisting language="java">mockMvc.perform(post("/hotels/{id}", 42).accept(MediaType.APPLICATION_JSON));</programlisting>
<para>In addition to all the HTTP methods, you can also perform file
upload requests, which internally creates an instance of
<classname>MockMultipartHttpServletRequest</classname>:</para>
<programlisting language="java">mockMvc.perform(fileUpload("/doc").file("a1", "ABC".getBytes("UTF-8")));
</programlisting>
<programlisting language="java">mockMvc.perform(fileUpload("/doc").file("a1", "ABC".getBytes("UTF-8")));</programlisting>
<para>Query string parameters can be specified in the URI
template:</para>
<programlisting language="java">mockMvc.perform(get("/hotels?foo={foo}", "bar"));
</programlisting>
<programlisting language="java">mockMvc.perform(get("/hotels?foo={foo}", "bar"));</programlisting>
<para>Or by adding Servlet request parameters:</para>
<programlisting language="java">mockMvc.perform(get("/hotels").param("foo", "bar"));
</programlisting>
<programlisting language="java">mockMvc.perform(get("/hotels").param("foo", "bar"));</programlisting>
<para>If application code relies on Servlet request parameters, and
doesn't check the query string, as is most often the case, then it
@ -3308,8 +3414,7 @@ public class AccountTests { @@ -3308,8 +3414,7 @@ public class AccountTests {
<function>servletPath</function> accordingly so that request mappings
will work:</para>
<programlisting language="java">mockMvc.perform(get("/app/main/hotels/{id}").contextPath("/app").servletPath("/main"))
</programlisting>
<programlisting language="java">mockMvc.perform(get("/app/main/hotels/{id}").contextPath("/app").servletPath("/main"))</programlisting>
<para>Looking at the above example, it would be cumbersome to set the
contextPath and servletPath with every performed request. That's why
@ -3326,9 +3431,7 @@ public class AccountTests { @@ -3326,9 +3431,7 @@ public class AccountTests {
.defaultRequest(get("/")
.contextPath("/app").servletPath("/main")
.accept(MediaType.APPLICATION_JSON).build();
}
}</programlisting>
}</programlisting>
<para>The above properties will apply to every request performed
through the <classname>MockMvc</classname>. If the same property is
@ -3345,8 +3448,7 @@ public class AccountTests { @@ -3345,8 +3448,7 @@ public class AccountTests {
<function>.andExpect(..)</function> after call to perform the
request:</para>
<programlisting language="java">mockMvc.perform(get("/accounts/1")).andExpect(status().isOk());
</programlisting>
<programlisting language="java">mockMvc.perform(get("/accounts/1")).andExpect(status().isOk());</programlisting>
<para><literal>MockMvcResultMatchers.*</literal> defines a number of
static members, some of which return types with additional methods,
@ -3369,8 +3471,7 @@ public class AccountTests { @@ -3369,8 +3471,7 @@ public class AccountTests {
<programlisting language="java">
mockMvc.perform(post("/persons"))
.andExpect(status().isOk())
.andExpect(model().attributeHasErrors("person"));
</programlisting>
.andExpect(model().attributeHasErrors("person"));</programlisting>
<para>Many times when writing tests, it's useful to dump the result of
the performed request. This can be done as follows, where
@ -3518,7 +3619,7 @@ mockServer.verify();</programlisting> @@ -3518,7 +3619,7 @@ mockServer.verify();</programlisting>
shown below:</para>
<programlisting language="java">import static org.junit.Assert.assertEquals;
<lineannotation>// import ...</lineannotation>
// import ...
<emphasis role="bold">@ContextConfiguration</emphasis>
public abstract class AbstractClinicTests <emphasis role="bold">extends AbstractTransactionalJUnit4SpringContextTests</emphasis> {
@ -3535,10 +3636,10 @@ public abstract class AbstractClinicTests <emphasis role="bold">extends Abstract @@ -3535,10 +3636,10 @@ public abstract class AbstractClinicTests <emphasis role="bold">extends Abstract
assertEquals("Leary", v1.getLastName());
assertEquals(1, v1.getNrOfSpecialties());
assertEquals("radiology", (v1.getSpecialties().get(0)).getName());
<lineannotation>// ...</lineannotation>
// ...
}
<lineannotation>// ...</lineannotation>
// ...
}</programlisting>
<para>Notes:</para>
@ -3608,8 +3709,7 @@ public abstract class AbstractClinicTests <emphasis role="bold">extends Abstract @@ -3608,8 +3709,7 @@ public abstract class AbstractClinicTests <emphasis role="bold">extends Abstract
<literal>AbstractClinicTests-context.xml</literal>.</para>
<programlisting language="java"><emphasis role="bold">@ContextConfiguration</emphasis>
public class HibernateClinicTests extends AbstractClinicTests { }
</programlisting>
public class HibernateClinicTests extends AbstractClinicTests { }</programlisting>
<para>In a large-scale application, the Spring configuration is often
split across multiple files. Consequently, configuration locations are

Loading…
Cancel
Save