Following is the subject under test RestClient.java
package com.demo.mockito;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.Validate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.demo.sample1.RestClient;
import com.demo.sample2.AboutApi;
import com.demo.sample3.ServiceInfo;
import com.demo.sample4.FeatureRepo;
@Component
@Slf4j
public class RestClient {
@Value("${test.api.baseURL:http://localhost:80}")
private String baseURL;
private static String ACTIVE = "ACTIVE";
@Autowired(required = false)
private TokenService tokenService;
private FeatureRepo featureRepo;
RestClient(FeatureRepo featureRepo) {
this.FeatureRepo = featureRepo;
}
public boolean isEnabled() {
AboutApi aboutApi = new AboutApi(getApiClient());
ServiceInfo serviceInfo = aboutApi.getMultiSiteServiceInfo();
Validate.notNull(serviceInfo);
return ACTIVE.equals(serviceInfo.getStatus());
}
private ApiClient getApiClient() {
ApiClient apiClient = new ApiClient();
apiClient.setBasePath(baseURL);
return apiClient;
}
}
And this one is the test RestClientTest.java
package com.demo.mockito;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.powermock.modules.junit4.PowerMockRunner;
import com.demo.sample1.RestClient;
import com.demo.sample2.AboutApi;
import com.demo.sample3.ServiceInfo;
import com.demo.sample4.FeatureRepo;
@RunWith(PowerMockRunner.class)
public class RestClientTest {
@InjectMocks private RestClient restClient;
@Mock private AboutApi aboutApiClient;
@Mock ServiceInfo serviceInfo;
@Mock FeatureRepo featureRepo;
@Before
public void init() throws ApiException {
when(aboutApiClient.getServiceInfo()).thenReturn(serviceInfo);
when(serviceInfo.getStatus()).thenReturn("ACTIVE");
}
@Test
public void testIsEnabled() throws ApiException {
boolean status = restClient.isEnabled();
assertTrue(status);
}
}
When I run the test, ideally as it reaches the 2nd line of RestClient.java's isEnabled method, the output should be mocked as stated in 1st line of @Before but it tries to call the real method leading to IllegalArgumentException.
Can someone please tell me how can I properly mock that call without doing any changes in the file RestClient.java ?
Edit: Updated
I have issue in the line AboutApi aboutApi = new AboutApi(getApiClient()). Here it is calling a new instance instead of using the one which I mocked. I want to know how can I insert my mocked instance of AboutApi without touching RestClient.java
In that case you have to take a look at PowerMockito's whenNew functionality.
You will have to add the @PrepareForTest
annotation so
that it includes the class that needs to be modified, in your case RestClient
.
@RunWith(PowerMockRunner.class)
@PrepareForTest(RestClient.class)
Not sure whether that is a typo in your question,
but the method you need to define behaviour for should be getMultiSiteServiceInfo
instead of getServiceInfo
.
@Test
public void testIsEnabled() throws Exception {
Mockito.when(aboutApiClient.getMultiSiteServiceInfo()).thenReturn(serviceInfo);
Mockito.when(serviceInfo.getStatus()).thenReturn("ACTIVE");
PowerMockito.whenNew(AboutApi.class)
.withAnyArguments()
.thenReturn(aboutApiClient);
boolean status = restClient.isEnabled();
Assert.assertTrue(status);
}
You can replace withAnyArguments()
with withArguments(Mockito.any(ApiClient.class))
if you want to be more specific.
Note however that the fields tokenService
and baseUrl
in your RestClient
class will be null
.