4

I have configuration class:

@ConfigurationProperties(prefix = "myConfig")
public class MyConfig {
    protected String config;
}

My service uses this config class (That gets the value from application.yml):

@Service
public class myService {

    @Inject
    private MyConfig myConfig;

    Public String getInfo (String param) {
        if (isEmpty(param)) { throw new InvalidParameterException; }
        return myConfig.getConfig();
    }
}

I'm trying to test it with Mockito:

@RunWith(MockitoJUnitRunner.class)
public class myTest {

    @InjectMocks
    private MyService myService;

    @Mock
    private MyConfig myConfig;

    @Test
    public void myTest1() {
        myService.getInfo("a");
    }

    @Test
    public void myTest2() {
        assertThrows(InvalidParameterException.class, ()->myService.getInfo(null));
    }
}

myTest fails since the config class is mocked, thus has null values. What is the right way to test configuration class with Mockito?

Edit: I have a number of config classes like the one above that are being used in myService.

2
  • You have to define the behaviour of your myConfig mock. For example: when(myConfig.getConfig()).thenReturn( ... ); where ... is whatever you want to return. However you need a method in the MyConfig object if you want to define behaviour. You also might want to add some code to your question so we can see what MyService is actually doing. Commented Aug 1, 2019 at 8:01
  • You might want to take a look at this question: stackoverflow.com/questions/31745168/… Commented Aug 1, 2019 at 8:25

3 Answers 3

2

You need to create getter which then can be mocked by Mockito.

@ConfigurationProperties(prefix = "myConfig")
public class MyConfig {
    protected String config;

    public String getConfig() {
        return config;
    }
}

.

@RunWith(MockitoJUnitRunner.class)
public class myTest {

    @InjectMocks
    private MyService myService;

    @Mock
    private MyConfig myConfig;

    @Before
    private void initializeConfig() {
        when(myConfig.getConfig()).thenReturn("someValue");
    }

    @Test
    public void myTest1() {
        myService.getInfo("a");
    }
}

But if you don't want to set the value explicitly in test, you should create a Spring integration test which would create the whole context and use the real objects. But this is out of scope of this question.

Sign up to request clarification or add additional context in comments.

3 Comments

This config class gets the data from my application.yml, so I want to use the data from this file and don't want to set it manually in the test. Is there a way to get it to set from the application.yml?
I'm afraid Mockito runner cannot do that. Maybe try to use SpringRunner.class which should create the whole context and inject the dependencies. It is possible that you would also need to create some Context used only in tests.
How can I use a real object?
0

You should mark MyConfig with @Configuration so that Spring creates a Spring bean in the application context.

you also need to use @RunWith(SpringRunner.class)

The SpringRunner provides support for loading a Spring ApplicationContext and having beans @Autowired into your test instance.

Also change @Inject with @Autowired because i am not sure how @inject will be supported by spring

Service Class

@Service
public class myService {

    @Autowired
    private MyConfig myConfig;

    Public String getInfo {
        return myConfig.getConfig();
    }
}

Test class

@RunWith(SpringRunner.class)
public class myTest {

    @Mock
    private MyService myService;

    @InjectMocks
    private MyConfig myConfig;

This is way you should get real object in test

EDIT

Considering you don't want to mock myservice then we should replace your test class with below and let me know

@RunWith(SpringRunner.class)
public class myTest {

@autowired
private MyService myService;

@Test
public void myTest1() {
    myService.getInfo("<NAME_OF_PROPERTIES>");
}

@Test
public void myTest2() {
    assertThrows(InvalidParameterException.class, ()->myService.getInfo(null));
}

17 Comments

I'm still getting a NullPointerException with these exceptions. How does that work? Doesn't InjectMocks gives you a mocked object with null values?
you can even use @autowired on MyConfig in test class and then get that instance setup with myService.setMyConfig(<<Autowired Myconfig Reference>>) .
@InjectMocks creates a real object and tries to inject the fields annotated with @Mock. However in your case you do not want to mock the MyService class (as you want to have the real values).
@psi: You switched the annotations in your example.
@second I agree.. i did it just to get real object Myconfig injected to service mock object
|
0

I had a similar issue, so I want to provide my solution, maybe will be helpful for someone, I had a test class that uses Mockito to mock some dependency, but I also needed to use a yaml and of course I didn't want to set values manually using "when(myConfig.getConfig()).thenReturn("someValue");"

I simply solved it by using SpringExtension along with MockitoExtension.

@EnableConfigurationProperties
@ContextConfiguration(classes = { MyConfig.class })
@Extensions({
        @ExtendWith(SpringExtension.class),
        @ExtendWith(MockitoExtension.class)
})
class MyTest {

    @Autowired
    private MyConfig myConfig;

}

for more details: How to test Externalized Configuration reading from yaml

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.