Introduce ActiveProfilesResolver in the TCF

Prior to this commit, the active bean definition profiles to use when
loading an ApplicationContext for tests could only be configured
declaratively (i.e., via hard-coded values supplied to the 'value' or
'profiles' attribute of @ActiveProfiles).

This commit makes it possible to programmatically configure active bean
definition profiles in tests via a new ActiveProfileResolver interface.
Custom resolvers can be registered via a new 'resolver' attribute
introduced in @ActiveProfiles.

Overview of changes:

 - Introduced a new ActiveProfilesResolver API.
 - Added a 'resolver' attribute to @ActiveProfiles.
 - Updated ContextLoaderUtils.resolveActiveProfiles() to support
   ActiveProfilesResolvers.
 - Documented these new features in the reference manual.
 - Added new content to the reference manual regarding the
   'inheritProfiles' attribute of @ActiveProfiles
 - Removed the use of <lineannotation> Docbook markup in the testing
   chapter of the reference manual for Java code examples in order to
   allow comments to have proper syntax highlighting in the generated
   HTML and PDF.

Issue: SPR-10338
This commit is contained in:
Sam Brannen
2013-06-16 00:01:34 +02:00
parent d4dcf4e4ec
commit 044f51283b
14 changed files with 731 additions and 137 deletions

View File

@@ -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 {
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 {
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 {

View File

@@ -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;
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 {
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 {
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 {
private static class OverriddenInitializersAndClassesBar extends InitializersFoo {
}
// --- @ContextHierarchy ---------------------------------------------------
@ContextConfiguration("foo.xml")
@ContextHierarchy(@ContextConfiguration("bar.xml"))
private static class SingleTestClassWithContextConfigurationAndContextHierarchy {

View File

@@ -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,//
DefaultLoaderBeanOverridingExplicitConfigClassesInheritedTests.class,//
DefaultProfileAnnotationConfigTests.class,//
DevProfileAnnotationConfigTests.class,//
DevProfileResolverAnnotationConfigTests.class,//
DefaultProfileXmlConfigTests.class,//
DevProfileXmlConfigTests.class,//
DevProfileResolverXmlConfigTests.class,//
ExpectedExceptionSpringRunnerTests.class,//
TimedSpringRunnerTests.class,//
RepeatedSpringRunnerTests.class,//

View File

@@ -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" };
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -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 {
}

View File

@@ -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" };
}
}

View File

@@ -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() };
}
}

View File

@@ -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()));
}
}

View File

@@ -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" };
}
}

View File

@@ -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;
// Note: the following 'multi-line' layout is for enhanced code readability.
@SuiteClasses({//
DefaultProfileXmlConfigTests.class,//
DevProfileXmlConfigTests.class //
DevProfileXmlConfigTests.class,//
DevProfileResolverXmlConfigTests.class //
})
public class ProfileXmlConfigTestSuite {
}