5

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
  • Do you have application.properties/application.yml in your test directory? If you have - you should put property of @Value you need there Commented Oct 21, 2021 at 6:26
  • You could simply switch to constructor injection… Commented Oct 21, 2021 at 6:27
  • @Alex those config files are only processed by Spring in integration tests, not standalone unit tests. Commented Oct 21, 2021 at 6:29
  • I don't think this file type "yaml" or "properties" is playing any role here. @Alex Anyway its "yaml" Commented Oct 21, 2021 at 6:53

4 Answers 4

5

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");
Sign up to request clarification or add additional context in comments.

2 Comments

Perfect answer. This is what I just tried and it worked.
This is a good answer but my problem is that i have 6 fields in application.properties and they are changeable so how to read them from there if possible without turning this in integration test?
2

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;
    }
}

Comments

2

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.

Comments

0

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);

1 Comment

This is basically the already accepted answer with the added hint of not loading the entire application context.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.