Preserve ordering of inlined props in @TestPropertySource

The initial implementation for adding inlined properties configured via
@TestPropertySource to the context's environment did not preserve the
order in which the properties were physically declared. This makes
@TestPropertySource a poor testing facility for mimicking the
production environment's configuration if the property source mechanism
used in production preserves ordering of property names -- which is the
case for YAML-based property sources used in Spring Boot, Spring Yarn,
etc.

This commit addresses this issue by ensuring that the ordering of
inlined properties declared via @TestPropertySource is preserved.
Specifically, the original functionality has been refactored. extracted
from AbstractContextLoader, and moved to TestPropertySourceUtils where
it may later be made public for general purpose use in other frameworks.

Issue: SPR-12710
This commit is contained in:
Sam Brannen
2015-02-16 20:25:57 +01:00
parent add718d75c
commit d6a799ad4a
4 changed files with 170 additions and 89 deletions

View File

@@ -21,7 +21,10 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertySource;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -29,28 +32,31 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.junit.Assert.*;
/**
* Integration tests for {@link TestPropertySource @TestPropertySource}
* support with an inlined properties.
* Integration tests for {@link TestPropertySource @TestPropertySource} support with
* inlined properties.
*
* @author Sam Brannen
* @since 4.1
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@TestPropertySource(properties = { "foo = bar", "baz quux", "enigma: 42",
"x.y.z = a=b=c", "server.url = http://example.com", "key.value.1: key=value",
"key.value.2 key=value", "key.value.3 key:value" })
@TestPropertySource(properties = { "", "foo = bar", "baz quux", "enigma: 42", "x.y.z = a=b=c",
"server.url = http://example.com", "key.value.1: key=value", "key.value.2 key=value", "key.value.3 key:value" })
public class InlinedPropertiesTestPropertySourceTests {
@Autowired
protected Environment env;
private Environment env;
@Test
public void verifyPropertiesAreAvailableInEnvironment() {
public void propertiesAreAvailableInEnvironment() {
// Simple key/value pairs
assertEquals("bar", env.getProperty("foo"));
assertEquals("quux", env.getProperty("baz"));
assertEquals(42, env.getProperty("enigma", Integer.class).intValue());
// Values containing key/value delimiters (":", "=", " ")
assertEquals("a=b=c", env.getProperty("x.y.z"));
assertEquals("http://example.com", env.getProperty("server.url"));
assertEquals("key=value", env.getProperty("key.value.1"));
@@ -58,6 +64,28 @@ public class InlinedPropertiesTestPropertySourceTests {
assertEquals("key:value", env.getProperty("key.value.3"));
}
@Test
@SuppressWarnings("rawtypes")
public void propertyNameOrderingIsPreservedInEnvironment() {
String[] propertyNames = null;
ConfigurableEnvironment configurableEnvironment = (ConfigurableEnvironment) env;
for (PropertySource<?> propertySource : configurableEnvironment.getPropertySources()) {
if (propertySource instanceof EnumerablePropertySource) {
EnumerablePropertySource eps = (EnumerablePropertySource) propertySource;
if (eps.getName().startsWith("test properties")) {
propertyNames = eps.getPropertyNames();
break;
}
}
}
final String[] expectedPropertyNames = new String[] { "foo", "baz", "enigma", "x.y.z", "server.url",
"key.value.1", "key.value.2", "key.value.3" };
assertArrayEquals(expectedPropertyNames, propertyNames);
}
// -------------------------------------------------------------------

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,10 +16,16 @@
package org.springframework.test.context.support;
import java.util.Map;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.mock.env.MockEnvironment;
import org.springframework.mock.env.MockPropertySource;
import org.springframework.test.context.TestPropertySource;
import static org.hamcrest.CoreMatchers.*;
@@ -113,6 +119,41 @@ public class TestPropertySourceUtilsTests {
new String[] { "classpath:/baz.properties" }, new String[] { "key = value" });
}
/**
* @since 4.1.5
*/
@Test
@SuppressWarnings("rawtypes")
public void emptyInlinedProperty() {
ConfigurableEnvironment environment = new MockEnvironment();
MutablePropertySources propertySources = environment.getPropertySources();
propertySources.remove(MockPropertySource.MOCK_PROPERTIES_PROPERTY_SOURCE_NAME);
assertEquals(0, propertySources.size());
addInlinedPropertiesToEnvironment(environment, new String[] { " " });
assertEquals(1, propertySources.size());
assertEquals(0, ((Map) propertySources.iterator().next().getSource()).size());
}
/**
* @since 4.1.5
*/
@Test
public void inlinedPropertyWithMalformedUnicodeInValue() {
expectedException.expect(IllegalStateException.class);
expectedException.expectMessage("Failed to load test environment property");
addInlinedPropertiesToEnvironment(new MockEnvironment(), new String[] { "key = \\uZZZZ" });
}
/**
* @since 4.1.5
*/
@Test
public void inlinedPropertyWithMultipleKeyValuePairs() {
expectedException.expect(IllegalStateException.class);
expectedException.expectMessage("Failed to load exactly one test environment property");
addInlinedPropertiesToEnvironment(new MockEnvironment(), new String[] { "a=b\nx=y" });
}
// -------------------------------------------------------------------