1. Overview
In this tutorial, we’ll have a look at various ways to override properties in Spring’s tests.
Spring actually provides a number of solutions for this, so we have quite a bit to explore here.
2. Dependencies
Of course, in order to work with Spring tests, we need to add a test dependency:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <version>2.1.6.RELEASE</version> <scope>test</scope> </dependency>
The spring-boot-starter-test dependency contains everything we need to override the property value in the tests.
3. Setup
First, we’ll have to create a class in the application that will use our properties:
@Component public class PropertySourceResolver { @Value("${example.firstProperty}") private String firstProperty; @Value("${example.secondProperty}") private String secondProperty; public String getFirstProperty() { return firstProperty; } public String getSecondProperty() { return secondProperty; } }
Next, let’s assign values to them. We can do that by creating the application.properties in the src/main/resources:
example.firstProperty=defaultFirst example.secondProperty=defaultSecond
4. Overriding a Property File
Now, we’ll override properties by putting the property file in the test resources. This file must be on the same classpath as the default one.
Additionally, it should contain all the property keys specified in the default file. Therefore, we’ll add the application.properties file into the src/test/java/resources:
example.firstProperty=file example.secondProperty=file
Let’s also add the test that will make use of our solution:
@RunWith(SpringRunner.class) @SpringBootTest public class TestResourcePropertySourceResolverIntegrationTest { @Autowired private PropertySourceResolver propertySourceResolver; @Test public void shouldTestResourceFile_overridePropertyValues() { String firstProperty = propertySourceResolver.getFirstProperty(); String secondProperty = propertySourceResolver.getSecondProperty(); assertEquals("file", firstProperty); assertEquals("file", secondProperty); } }
This method is very effective when we want to override multiple properties from the file.
And, if we didn’t put the example.secondProperty in the file, the application context wouldn’t discover this property.
5. Spring Profiles
In this section, we’ll learn how to deal with our issue by using Spring Profiles. Unlike the previous method, this one merges properties from the default file and the profiled file.
First, let’s create an application–test.properties file in the src/test/java/resources:
example.firstProperty=profile
After that, we’ll create a test that will use the test profile:
@RunWith(SpringRunner.class) @SpringBootTest @ActiveProfiles("test") public class ProfilePropertySourceResolverIntegrationTest { @Autowired private PropertySourceResolver propertySourceResolver; @Test public void shouldProfiledProperty_overridePropertyValues() { String firstProperty = propertySourceResolver.getFirstProperty(); String secondProperty = propertySourceResolver.getSecondProperty(); assertEquals("profile", firstProperty); assertEquals("defaultSecond", secondProperty); } }
This approach allows us to use both default and test values. Therefore, this is a great method when we need to override multiple properties from a file but we still want to use the default ones.
Additionally, we can learn more about Spring profiles in our Spring Profiles tutorial.
6. @SpringBootTest
Another way to override the property value is to use the @SpringBootTest annotation:
@RunWith(SpringRunner.class) @SpringBootTest(properties = { "example.firstProperty=annotation" }) public class SpringBootPropertySourceResolverIntegrationTest { @Autowired private PropertySourceResolver propertySourceResolver; @Test public void shouldSpringBootTestAnnotation_overridePropertyValues() { String firstProperty = propertySourceResolver.getFirstProperty(); String secondProperty = propertySourceResolver.getSecondProperty(); Assert.assertEquals("annotation", firstProperty); Assert.assertEquals("defaultSecond", secondProperty); } }
As we can see, the example.firstProperty has been overridden while the example.secondProperty hasn’t been. Therefore, this is a great solution when we need to override only specific properties for the test. This is the only method that requires the usage of Spring Boot.
7. TestPropertySourceUtils
In this section, we’ll learn how to override properties by using the TestPropertySourceUtils class in the ApplicationContextInitializer.
The TestPropertySourceUtils comes with two methods that we can use to define a different property value.
Let’s create an initializer class that we’ll use in our test:
public class PropertyOverrideContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { static final String PROPERTY_FIRST_VALUE = "contextClass"; @Override public void initialize(ConfigurableApplicationContext configurableApplicationContext) { TestPropertySourceUtils.addInlinedPropertiesToEnvironment( configurableApplicationContext, "example.firstProperty=" + PROPERTY_FIRST_VALUE); TestPropertySourceUtils.addPropertiesFilesToEnvironment( configurableApplicationContext, "context-override-application.properties"); } }
Next, we’ll add the context-override-application.properties file into src/test/resources:
example.secondProperty=contextFile
Finally, we should create a test class that will use our initializer:
@RunWith(SpringRunner.class) @ContextConfiguration( initializers = PropertyOverrideContextInitializer.class, classes = Application.class) public class ContextPropertySourceResolverIntegrationTest { @Autowired private PropertySourceResolver propertySourceResolver; @Test public void shouldContext_overridePropertyValues() { final String firstProperty = propertySourceResolver.getFirstProperty(); final String secondProperty = propertySourceResolver.getSecondProperty(); assertEquals(PropertyOverrideContextInitializer.PROPERTY_FIRST_VALUE, firstProperty); assertEquals("contextFile", secondProperty); } }
The example.firstProperty has been overridden from the inlined method.
The example.secondProperty has been overridden from the specific file in the second method. This approach allows us to define different property values when initializing the context.
8. Conclusion
In this tutorial, we’ve focused on the multiple ways that we can use to override properties in our tests.
We’ve also discovered when to use each solution or in some cases when to mix them.
We, of course, have the @TestPropertySource annotation at our disposal as well.
As always, the code for examples is available over on GitHub.