Spring Boot
ConfigurationProperties
Autowired
Unit Testing
Java Development

How to test Classes with ConfigurationProperties and Autowired

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Testing classes that use @ConfigurationProperties and @Autowired works best when you separate two concerns: property binding and business logic. One test should verify that Spring binds configuration correctly, and another should verify that your class behaves correctly once those dependencies are injected.

Prefer Constructor Injection First

The easiest classes to test are the ones that use constructor injection. Spring can still autowire them in production, but plain unit tests can instantiate them directly with mocks or test values.

java
1import org.springframework.boot.context.properties.ConfigurationProperties;
2
3@ConfigurationProperties(prefix = "app")
4public class AppProperties {
5    private String name;
6    private int timeoutSeconds;
7
8    public String getName() { return name; }
9    public void setName(String name) { this.name = name; }
10    public int getTimeoutSeconds() { return timeoutSeconds; }
11    public void setTimeoutSeconds(int timeoutSeconds) { this.timeoutSeconds = timeoutSeconds; }
12}
java
1public class GreetingService {
2    private final AppProperties properties;
3
4    public GreetingService(AppProperties properties) {
5        this.properties = properties;
6    }
7
8    public String greeting() {
9        return "Hello from " + properties.getName();
10    }
11}

That design gives you a clean seam for both Spring tests and plain unit tests.

Test Property Binding in a Small Spring Context

You do not always need @SpringBootTest. For focused property-binding tests, a small context is faster and clearer.

java
1import org.junit.jupiter.api.Test;
2import org.springframework.boot.autoconfigure.AutoConfigurations;
3import org.springframework.boot.context.properties.EnableConfigurationProperties;
4import org.springframework.boot.test.context.runner.ApplicationContextRunner;
5import org.springframework.context.annotation.Configuration;
6
7import static org.assertj.core.api.Assertions.assertThat;
8
9class AppPropertiesTest {
10    private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
11        .withConfiguration(AutoConfigurations.of(TestConfig.class))
12        .withPropertyValues(
13            "app.name=Codemia",
14            "app.timeout-seconds=15"
15        );
16
17    @Test
18    void bindsProperties() {
19        contextRunner.run(context -> {
20            AppProperties props = context.getBean(AppProperties.class);
21            assertThat(props.getName()).isEqualTo("Codemia");
22            assertThat(props.getTimeoutSeconds()).isEqualTo(15);
23        });
24    }
25
26    @Configuration
27    @EnableConfigurationProperties(AppProperties.class)
28    static class TestConfig {
29    }
30}

This verifies the binding rules without loading your whole application.

Test the Service as a Plain Unit Test

Once property binding is verified separately, test the service without Spring.

java
1import org.junit.jupiter.api.Test;
2
3import static org.assertj.core.api.Assertions.assertThat;
4
5class GreetingServiceTest {
6    @Test
7    void usesConfiguredName() {
8        AppProperties props = new AppProperties();
9        props.setName("Codemia");
10        props.setTimeoutSeconds(15);
11
12        GreetingService service = new GreetingService(props);
13
14        assertThat(service.greeting()).isEqualTo("Hello from Codemia");
15    }
16}

This kind of test is faster than starting a Spring context and it fails for business-logic reasons, not framework wiring noise.

When @SpringBootTest Is Appropriate

Use @SpringBootTest when you genuinely need integration across several auto-configured beans, profiles, converters, or externalized configuration layers.

java
1import org.junit.jupiter.api.Test;
2import org.springframework.beans.factory.annotation.Autowired;
3import org.springframework.boot.test.context.SpringBootTest;
4
5import static org.assertj.core.api.Assertions.assertThat;
6
7@SpringBootTest(properties = {
8    "app.name=IntegrationApp",
9    "app.timeout-seconds=30"
10})
11class GreetingServiceIntegrationTest {
12    @Autowired
13    private GreetingService service;
14
15    @Test
16    void loadsServiceWithBoundProperties() {
17        assertThat(service.greeting()).isEqualTo("Hello from IntegrationApp");
18    }
19}

This is heavier, but useful when you want confidence that the real wiring path works.

Avoid Field Injection in New Code

Field injection is testable, but it is harder to reason about and encourages reflection-based setup in unit tests. Constructor injection makes dependencies explicit and reduces the need for Spring in simple tests.

If you inherit field-injected code, you can still test it with @SpringBootTest or ReflectionTestUtils, but that is usually a sign the class design can be improved.

Common Pitfalls

The biggest mistake is using @SpringBootTest for every class test. That makes the suite slower and blurs the difference between binding problems and business-logic problems.

Another issue is testing @ConfigurationProperties only indirectly through service behavior. When binding and logic are mixed in one test, failures become harder to diagnose.

Developers also forget to enable the configuration-properties class in narrow tests. If Spring never registers the properties bean, the test does not prove anything about binding.

Finally, field injection makes unit testing more awkward than it needs to be. Prefer constructor injection so dependencies are explicit and easy to supply.

Summary

  • Test property binding and service logic as separate concerns.
  • Use constructor injection to keep classes easy to instantiate in unit tests.
  • Prefer small context tests such as ApplicationContextRunner for @ConfigurationProperties.
  • Use @SpringBootTest only when full integration is the thing you actually want to verify.
  • Avoid field injection in new code because it makes tests less direct.

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.