5

I have a class that Autowires another class with @ConfigurationProperties.

Class with @ConfigurationProperties

@ConfigurationProperties(prefix = "report")
public class SomeProperties {
    private String property1;
    private String property2;
...

Class that Autowires above class SomeProperties

@Service
@Transactional
public class SomeService {
    ....
    @Autowired
    private SomeProperties someProperties;
    .... // There are other things

Now, I want to test SomeService class and in my test class when I mock SomeProperties class, I am getting null value for all the properties.

Test class

@RunWith(SpringRunner.class)
@SpringBootTest(classes = SomeProperties.class)
@ActiveProfiles("test")
@EnableConfigurationProperties
public class SomeServiceTest {
    @InjectMocks
    private SomeService someService;

    @Mock // I tried @MockBean as well, it did not work
    private SomeProperties someProperties;

How can I mock SomeProperties having properties from application-test.properties file.

1
  • 1
    Use constructor injection, not field injection. Commented Sep 11, 2020 at 14:56

3 Answers 3

4

You are not mocking SomeProperties if you intend to bind values from a properties file, in which case an actual instance of SomeProperties would be provided.

Mock:

@RunWith(MockitoJUnitRunner.class)
public class SomeServiceTest {

    @InjectMocks
    private SomeService someService;

    @Mock
    private SomeProperties someProperties;

    @Test
    public void foo() {
        // you need to provide a return behavior whenever someProperties methods/props are invoked in someService
        when(someProperties.getProperty1()).thenReturn(...)
    }

No Mock (someProperties is an real object that binds its values from some propertysource):

@RunWith(SpringRunner.class)
@EnableConfigurationProperties(SomeConfig.class)
@TestPropertySource("classpath:application-test.properties")
public class SomeServiceTest {
   
    private SomeService someService;

    @Autowired
    private SomeProperties someProperties;

    @Before
    public void setup() {
        someService = new someService(someProperties); // Constructor Injection
    }
    ...
Sign up to request clarification or add additional context in comments.

5 Comments

Do we need constructor injection for the autowired property
@12kadir12 What''s being @Autowired here doesn't have dependency on other Beans. So no. But in the case where dependency beans are present in the @Autowired bean, you could mock the dependency beans with @MockBean and provide stubbing for them.
I tried this solution but it doesn't work, the only difference is that I am using the .yml file instead of the properties file. Maybe the spring boot version is old since the project is legacy :) Do you have any idea?
@12kadir12 the reason is @TestPropertySource does not support YAML property files. Instead of this annotation you have provide special initializer via @ContextConfiguration(initializers = ConfigDataApplicationContextInitializer.class) or ConfigFileApplicationContextInitializer.class if you're using Spring Boot older than 2.4.
@NikitaKobtsev thank you for the explanation. I changed my yaml property files with original ones. but now, i know why i couldn't use @ TestPropertySource :)
3

You need to stub all the property values in @Test/@Before methods of SomeServiceTest.java like :

ReflectionTestUtils.setField(someProperties, "property1", "value1");

ReflectionTestUtils.setField(object, name, value);

                         

You can also mock the reponse for dependent classes via Mockito.when()

Comments

1

If you are using @Mock , you need to stub the values as well. By default the value will be null for all the properties.

Comments

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.