Christian Vincenzo Traina
Christian Vincenzo Traina

Reputation: 10464

@Value properties are always null in JUnit test

I'm writing a few unit tests for a Spring application that can be run with two different configurations. The two different configurations are given by two application.properties file. I need to write tests twice for each class, since I need to verify that changes that work with a configuration don't impact the other one.

For this reason I created two files in the directory:

src/test/resources/application-configA.properties

src/test/resources/application-configB.properties

Then I tried to load them using two different values of @TestPropertySource:

@SpringBootTest
@TestPropertySource(locations = "classpath:application-configA.properties")
class FooTest {
  @InjectMock
  Foo foo;

  @Mock
  ExternalDao dao;

  // perform test
}

And the Foo class is this one:

@Service
public class Foo {
  @Autowired
  private External dao;

  methodToTest() {
    Properties.getExampleProperty();
    this.dao.doSomething(); // this needs to be mocked!
  }
}

While the class Properties is:

@Component
public class Properties {
  private static String example;

  @Value("${example:something}")
  public void setExampleProperty(String _example) {
    example = _example;
  }

  public static String getExampleProperty() {
    return example;
  }
}

The problem is that Properties.getExampleProperty() always returns null during the test, while it contains the correct value in the normal execution.

I've tried:

Nothing of these worked.

I've read this question's answers, but looks like something different and they did not help me

Upvotes: 8

Views: 13263

Answers (2)

Christian Vincenzo Traina
Christian Vincenzo Traina

Reputation: 10464

After many attempts, finally I found a solution. The problem was caused by using Spring 4 with JUnit 5, and even though it wasn't showing any warning or error, it wasn't able to load the Spring context. In all honesty, I don't know what @SpringBootTest was doing in practice.

The solution was about adding the spring-test-junit5 dependency as stated in this answer, then the following steps:

  • Remove the @SpringBootTest annotation
  • Add @ExtendWith(SpringExtension.class), importing the class from spring-test-junit5
  • Add @Import(Properties.class)

Now the annotations for the test look like this:

@ExtendWith(SpringExtension.class)
@PropertySource("classpath:application-configA.properties")
@TestPropertySource("classpath:application-configA.properties")
@Import(Properties.class)
class FooTest {

Upvotes: 4

Milan Desai
Milan Desai

Reputation: 1306

I recommend using @Before in order to set values in unit tests if it's for a whole class using org.springframework.test.util.ReflectionTestUtils,

However in order to do so you will have to inject Properties instance in test class

@InjectMocks Properties properties;
...
@Before
  public void setUp() {
    ReflectionTestUtils.setField(properties, "example", "something");
  }

alternatively you can use same ReflectionTestUtil in @Test too - I think

update: Your way of Using @TestPropertySource is definitely correct but there might be some conflict on using terminology location and properties, In my opinion I have see code doing,

@TestPropertySource(properties = "classpath:application-configA.properties")

Plus, have you tried adding @ActiveProfile('test') and @AutoConfigureMockMvc ?

Upvotes: 0

Related Questions