Junit 5 mockito unable to read properties file annotated with @Value in spring boot application

Viewed 2166

I am writing a junit test cases for one of component in spring boot application. That component is having @Value annotation and reading value from property file.

When I am running my Junit 5 (mockito) and controls goes to the component; the value is null.

What I have tried: I used @ExtendWith(SpringRunner) and changed @injectMocks to @Autowired and @mock to @MockBeans, but that is not I want (As its became integration test.)

Junit class:

@ExtendWith(MockitoExtension.class)
public class ItemMessageProcessorTest {

    private static final String VALUE1 = "Value 1";
    private static final String VALUE2 = "Value 2";
    private static final String VALUE3 = "Value 3";

    @InjectMocks
    private MyComponent component;

    

Component class:

@Slf4j
@Component
public class MyComponent {

    @Value("${my-val.second-val.final-val}")
    private String myValue;

This myValue is being used here in the same component class:

 public void myMethod(){
    myObject.setMyValue(Integer.parseInt(myValue));
}

What I was looking for is something like: If I can by any chance mock the parseInt, or load the values from test class itself. Any lead would be a great help. Note: I can't change anything in the component class.

4 Answers

You can just use Spring reflection utills method for setting the field value with @Value for unit test:

org.springframework.test.util.ReflectionTestUtils.setField(classUnderTest, "field", "value");

I would go for constructor injection in this case:

@Slf4j
@Component
public class MyComponent {

    private final String myValue;

    MyComponent(@Value("${my-val.second-val.final-val}" String myValue)) {
        this.myValue = myValue;
    }
}

Values from application.properties are loaded into Spring Application Context in these cases:

  • when application is running,
  • when Spring Integration tests are runnign.

In case of Unit tests properties are not loaded.

If you'd have a constructor injection you could set a value for tests and pass it to the constructor.

Most important thing, you don't want to load the entire Spring Application context to bind the properties automatically as this would hugely slow down the execution of the unit tests. Therefore, you cannot use @ExtendWith(SpringRunner).

You can make use of ReflectionTestUtils along with @ExtendWith(MockitoExtension.class) to bind the properties of MyComponent class.

org.springframework.test.util.ReflectionTestUtils.setField(MyComponent.class, "myValue", 1);

Related