Praveen Kumar
Praveen Kumar

Reputation: 453

How to inject from application context into a mock in Junit5 Mockito?

I must implement an Unit Test for MyUtility.class in my Java application. However, It has a dependency on MyConfig.class (It fetches configuration properties from application.yml file).

class MyUtility {

  MyConfig myConfig;

  @Autowired
  public MyUtility(MyConfig myConfig) {
   this.myConfig = myConfig;
  }

  public String methodA() {

    ... // use myConfig.getValue() to perform some operation

    methodB(); // call methodB()

    ...
  }

  public String methodB() { ... }
}
@Component
@ConfigurationProperties(prefix = "test")
class MyConfig {

  String value; // to map test.value from application.yml
}

Using JUnit5, I'm trying to test the functionality methodA. But, I don't need to test methodB . Hence, I'm mocking the response of methodB.

class ApplicationTests {

  @Mock
  MyConfig myConfig;

  @Mock
  MyUtility myUtility;

  ...

  @Test
  public void testMethodA() {

    Mockito.when(myUtility.methodB()).thenReturn("someValue");
    ...
  }
}

Since I've to mock MyUtility, I'm also having to mock MyConfig since it's a dependency (else myConfig shows up as null). But I don't want to mock MyConfig. I want methodA to use the value that is present in the application.yml file rather than mocking it.

Is it possible to inject the MyConfig from the application context into MyUtility mock ?

Upvotes: 0

Views: 2823

Answers (1)

second
second

Reputation: 4259

If I could autowire MyConfig into the mocked MyUtility, the code would work fine.

As long as you use the SpringExtension and setup your configuration/context correctly you can do that. Instead of mocking MyConfig add the autowired config to your testclass and pass that one to your creation of the MyUtility class.

The reason I am mocking that specific method is because that method (methodB) is making a network call and returning a response back to methodA. I don't care about the network call.

The problem is that you currently mock the class (and not only the method). As @PaulBenn already mentioned you want to use @Spy instead of @Mock.

A methodcall on a spy uses the real implementation as long as you have not defined different behaviour for it. A spy is normally created on a pre-existing instance of the object so all dependencies should be setup normally.

class ApplicationTests {

    @Mock
    MyConfig myConfig;

    @Test
    public void testMethodA() {

        ...
        MyUtility spy = Mockito.spy(new MyUtility(myConfig));
        Mockito.when(spy.methodB()).thenReturn("someValue");

        spy.methodA();
        ...
    }
}

Upvotes: 1

Related Questions