Spring Top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

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 applicationtest.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.

Spring bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

Leave a Reply

avatar
  Subscribe  
Notify of