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 @@
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -34,6 +34,7 @@ import java.lang.annotation.Target;
* @see SmartContextLoader * @see SmartContextLoader
* @see MergedContextConfiguration * @see MergedContextConfiguration
* @see ContextConfiguration * @see ContextConfiguration
* @see ActiveProfilesResolver
* @see org.springframework.context.ApplicationContext * @see org.springframework.context.ApplicationContext
* @see org.springframework.context.annotation.Profile * @see org.springframework.context.annotation.Profile
*/ */
@ -47,8 +48,8 @@ public @interface ActiveProfiles {
* Alias for {@link #profiles}. * Alias for {@link #profiles}.
* *
* <p>This attribute may <strong>not</strong> be used in conjunction * <p>This attribute may <strong>not</strong> be used in conjunction
* with {@link #profiles}, but it may be used <em>instead</em> of * with {@link #profiles} or {@link #resolver}, but it may be used
* {@link #profiles}. * <em>instead</em> of them.
*/ */
String[] value() default {}; String[] value() default {};
@ -56,11 +57,24 @@ public @interface ActiveProfiles {
* The bean definition profiles to activate. * The bean definition profiles to activate.
* *
* <p>This attribute may <strong>not</strong> be used in conjunction * <p>This attribute may <strong>not</strong> be used in conjunction
* with {@link #value}, but it may be used <em>instead</em> of * with {@link #value} or {@link #resolver}, but it may be used
* {@link #value}. * <em>instead</em> of them.
*/ */
String[] profiles() default {}; 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 * Whether or not bean definition profiles from superclasses should be
* <em>inherited</em>. * <em>inherited</em>.

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

@ -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 @@
package org.springframework.test.context; 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.annotation.Annotation;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.util.ArrayList; import java.util.ArrayList;
@ -42,6 +37,9 @@ import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils; 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 * Utility methods for working with {@link ContextLoader ContextLoaders} and
* {@link SmartContextLoader SmartContextLoaders} and resolving resource locations, * {@link SmartContextLoader SmartContextLoaders} and resolving resource locations,
@ -49,12 +47,14 @@ import org.springframework.util.StringUtils;
* initializers. * initializers.
* *
* @author Sam Brannen * @author Sam Brannen
* @author Michail Nikolaev
* @since 3.1 * @since 3.1
* @see ContextLoader * @see ContextLoader
* @see SmartContextLoader * @see SmartContextLoader
* @see ContextConfiguration * @see ContextConfiguration
* @see ContextConfigurationAttributes * @see ContextConfigurationAttributes
* @see ActiveProfiles * @see ActiveProfiles
* @see ActiveProfilesResolver
* @see ApplicationContextInitializer * @see ApplicationContextInitializer
* @see ContextHierarchy * @see ContextHierarchy
* @see MergedContextConfiguration * @see MergedContextConfiguration
@ -477,24 +477,43 @@ abstract class ContextLoaderUtils {
while (declaringClass != null) { while (declaringClass != null) {
ActiveProfiles annotation = declaringClass.getAnnotation(annotationType); ActiveProfiles annotation = declaringClass.getAnnotation(annotationType);
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
logger.trace(String.format("Retrieved @ActiveProfiles [%s] for declaring class [%s].", annotation, logger.trace(String.format("Retrieved @ActiveProfiles [%s] for declaring class [%s].", annotation,
declaringClass.getName())); declaringClass.getName()));
} }
validateActiveProfilesConfiguration(declaringClass, annotation);
String[] profiles = annotation.profiles(); String[] profiles = annotation.profiles();
String[] valueProfiles = annotation.value(); String[] valueProfiles = annotation.value();
Class<? extends ActiveProfilesResolver> resolverClass = annotation.resolver();
if (!ObjectUtils.isEmpty(valueProfiles) && !ObjectUtils.isEmpty(profiles)) { boolean resolverDeclared = !ActiveProfilesResolver.class.equals(resolverClass);
String msg = String.format("Test class [%s] has been configured with @ActiveProfiles' 'value' [%s] " boolean valueDeclared = !ObjectUtils.isEmpty(valueProfiles);
+ "and 'profiles' [%s] attributes. Only one declaration of active bean "
+ "definition profiles is permitted per @ActiveProfiles annotation.", declaringClass.getName(), if (resolverDeclared) {
ObjectUtils.nullSafeToString(valueProfiles), ObjectUtils.nullSafeToString(profiles)); ActiveProfilesResolver resolver = null;
logger.error(msg); try {
throw new IllegalStateException(msg); 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; profiles = valueProfiles;
} }
@ -511,6 +530,43 @@ abstract class ContextLoaderUtils {
return StringUtils.toStringArray(activeProfiles); 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 * Build the {@link MergedContextConfiguration merged context configuration} for
* the supplied {@link Class testClass} and {@code defaultContextLoaderClassName}, * 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.*;
* conjunction with cache keys used in {@link TestContext}. * conjunction with cache keys used in {@link TestContext}.
* *
* @author Sam Brannen * @author Sam Brannen
* @author Michail Nikolaev
* @since 3.1 * @since 3.1
* @see SpringRunnerContextCacheTests * @see SpringRunnerContextCacheTests
*/ */
@ -84,6 +85,7 @@ public class ContextCacheTests {
loadCtxAndAssertStats(FooBarProfilesTestCase.class, 1, 3, 1); loadCtxAndAssertStats(FooBarProfilesTestCase.class, 1, 3, 1);
loadCtxAndAssertStats(FooBarProfilesTestCase.class, 1, 4, 1); loadCtxAndAssertStats(FooBarProfilesTestCase.class, 1, 4, 1);
loadCtxAndAssertStats(BarFooProfilesTestCase.class, 1, 5, 1); loadCtxAndAssertStats(BarFooProfilesTestCase.class, 1, 5, 1);
loadCtxAndAssertStats(FooBarActiveProfilesResolverTestCase.class, 1, 6, 1);
} }
@Test @Test
@ -287,6 +289,19 @@ public class ContextCacheTests {
private static class BarFooProfilesTestCase { 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 }) @ContextHierarchy({ @ContextConfiguration })
private static class ClassHierarchyContextHierarchyLevel1TestCase { private static class ClassHierarchyContextHierarchyLevel1TestCase {

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

@ -16,10 +16,6 @@
package org.springframework.test.context; 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.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
@ -38,10 +34,15 @@ import org.springframework.test.context.support.DelegatingSmartContextLoader;
import org.springframework.test.context.support.GenericPropertiesContextLoader; import org.springframework.test.context.support.GenericPropertiesContextLoader;
import org.springframework.web.context.support.GenericWebApplicationContext; 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}. * Unit tests for {@link ContextLoaderUtils}.
* *
* @author Sam Brannen * @author Sam Brannen
* @author Michail Nikolaev
* @since 3.1 * @since 3.1
*/ */
public class ContextLoaderUtilsTests { public class ContextLoaderUtilsTests {
@ -606,8 +607,94 @@ public class ContextLoaderUtilsTests {
assertTrue(list.contains("cat")); 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 { private static class Enigma {
} }
@ -677,6 +764,80 @@ public class ContextLoaderUtilsTests {
private static class Animals extends LocationsBar { 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> { private static class FooInitializer implements ApplicationContextInitializer<GenericApplicationContext> {
@Override @Override
@ -707,6 +868,8 @@ public class ContextLoaderUtilsTests {
private static class OverriddenInitializersAndClassesBar extends InitializersFoo { private static class OverriddenInitializersAndClassesBar extends InitializersFoo {
} }
// --- @ContextHierarchy ---------------------------------------------------
@ContextConfiguration("foo.xml") @ContextConfiguration("foo.xml")
@ContextHierarchy(@ContextConfiguration("bar.xml")) @ContextHierarchy(@ContextConfiguration("bar.xml"))
private static class SingleTestClassWithContextConfigurationAndContextHierarchy { 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
import org.springframework.test.context.junit4.orm.HibernateSessionFlushingTests; 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.DefaultProfileAnnotationConfigTests;
import org.springframework.test.context.junit4.profile.annotation.DevProfileAnnotationConfigTests; 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.DefaultProfileXmlConfigTests;
import org.springframework.test.context.junit4.profile.xml.DevProfileResolverXmlConfigTests;
import org.springframework.test.context.junit4.profile.xml.DevProfileXmlConfigTests; import org.springframework.test.context.junit4.profile.xml.DevProfileXmlConfigTests;
/** /**
@ -77,8 +79,10 @@ StandardJUnit4FeaturesTests.class,//
DefaultLoaderBeanOverridingExplicitConfigClassesInheritedTests.class,// DefaultLoaderBeanOverridingExplicitConfigClassesInheritedTests.class,//
DefaultProfileAnnotationConfigTests.class,// DefaultProfileAnnotationConfigTests.class,//
DevProfileAnnotationConfigTests.class,// DevProfileAnnotationConfigTests.class,//
DevProfileResolverAnnotationConfigTests.class,//
DefaultProfileXmlConfigTests.class,// DefaultProfileXmlConfigTests.class,//
DevProfileXmlConfigTests.class,// DevProfileXmlConfigTests.class,//
DevProfileResolverXmlConfigTests.class,//
ExpectedExceptionSpringRunnerTests.class,// ExpectedExceptionSpringRunnerTests.class,//
TimedSpringRunnerTests.class,// TimedSpringRunnerTests.class,//
RepeatedSpringRunnerTests.class,// RepeatedSpringRunnerTests.class,//

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

@ -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 @@
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -31,7 +31,8 @@ import org.junit.runners.Suite.SuiteClasses;
// Note: the following 'multi-line' layout is for enhanced code readability. // Note: the following 'multi-line' layout is for enhanced code readability.
@SuiteClasses({// @SuiteClasses({//
DefaultProfileAnnotationConfigTests.class,// DefaultProfileAnnotationConfigTests.class,//
DevProfileAnnotationConfigTests.class // DevProfileAnnotationConfigTests.class,//
DevProfileResolverAnnotationConfigTests.class //
}) })
public class ProfileAnnotationConfigTestSuite { public class ProfileAnnotationConfigTestSuite {
} }

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

@ -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 @@
/*
* 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 @@
/*
* 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 @@
/*
* 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 @@
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -31,7 +31,8 @@ import org.junit.runners.Suite.SuiteClasses;
// Note: the following 'multi-line' layout is for enhanced code readability. // Note: the following 'multi-line' layout is for enhanced code readability.
@SuiteClasses({// @SuiteClasses({//
DefaultProfileXmlConfigTests.class,// DefaultProfileXmlConfigTests.class,//
DevProfileXmlConfigTests.class // DevProfileXmlConfigTests.class,//
DevProfileResolverXmlConfigTests.class //
}) })
public class ProfileXmlConfigTestSuite { public class ProfileXmlConfigTestSuite {
} }

318
src/reference/docbook/testing.xml

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

Loading…
Cancel
Save