Authors Top

If you have a few years of experience in the Java ecosystem, and you’d like to share that with the community, have a look at our Contribution Guidelines.

Spring Top – Temp

Get started with Spring 5 and Spring Boot 2, through the reference Learn Spring course:

>> LEARN SPRING
Lightrun – Third Party Code
announcement - icon

Flakiness in REST requests is a common issue. A request can get a 200 OK in one scenario and a 409 next time. Sometimes a request can even succeed and fail intermittently on the same exact request. In short, working over HTTP can be a bit of a mess without solid tooling.

Also, while it’s easy enough to debug these issues locally when developing the application, we’re talking about production here - we can’t afford the downtime while you’re stepping in and out of code. Uptime is kind of the whole point.

With Lightrun, you can get the same level of access you get with a local debugger or profiler - no downtime required. You can add logs, metrics, and snapshots (think breakpoints, but without stopping the running service), in a safe and read-only manner - without redeploying, restarting, or even stopping the running service. Performance and security are maintained throughout the process.

Learn how to debug a live REST API (built with Spring, of course), using Lightrun, in this 5-minute tutorial:

>> Debugging REST Requests in Spring-Based applications using the Lightrun Platform

1. Overview

In this tutorial, we'll look at various ways to override the 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.7.2</version>
    <scope>test</scope>
</dependency>

This dependency also includes JUnit 5 for us.

3. Setup

First, we'll 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, we'll assign values to them. We can do this 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/resources:

example.firstProperty=file
example.secondProperty=file

Let's also add the test that will make use of our solution:

@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 don't put the example.secondProperty in the file, the application context won't discover this property.

5. Spring Profiles

In this section, we'll learn how to handle 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/resources:

example.firstProperty=profile

Then we'll create a test that will use the test profile:

@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 too.

We can learn more about Spring profiles in our Spring Profiles article.

6. @SpringBootTest

Another way to override the property value is to use the @SpringBootTest annotation:

@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 use 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:

@SpringBootTest
@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 article, we focused on the multiple ways we can override properties in our tests. We also discussed when to use each solution, or in some cases, when to mix them.

Of course, we have the @TestPropertySource annotation at our disposal as well.

As always, the code for the examples in this article is available over on GitHub.

Spring bottom

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:

>> THE COURSE
Junit footer banner
Comments are closed on this article!