Search code examples
javaunit-testingmockitotestng

Mockito mock a method calls actual method


I have been trying to mock a method of a class. The method is reading a configuration from file. The file consists of a URI of a service. Method is reading URI from file and creating a WebTarget object. I have been running a testng mockito test case and I am trying to return a string from a mock method when this method is called. Problem is whenever this method is called then actual method is called and it tries to read the file. However, (Correct me if I am wrong) it should not call the actual method and returns the mocked response. Somehow, it is not working. Below is the code for the test

@Mock
private ExternalApiConfig externalApiConfig = null;
public CisAccountServiceImpl cisAccoutService;

@BeforeMethod
public void init() {
    MockitoAnnotations.initMocks(this);
    externalApiConfig = Mockito.mock(CisApiConfig.class);
}

private void testUpdateServiceAddressCoordinates(Account account) throws IOException {
    Mockito.when(externalApiConfig.getExternalUrl()).thenReturn("http://localhost:8080/serviceURI/");
    cisAccoutService = new CisAccountServiceImpl();
    assertThat(account, is(notNullValue()));
    List<PremiseExtension> premiseExtensions = account.getPremise().getPremiseExtension();
    assertThat(premiseExtensions.size(), is(30));
    String geoXSettingName = "value2";
    String geoYSettingName = "value3";
    Double lat = 24.0;
    Double lng = -98.0;
    boolean updated = cisAccoutService.updateAccountGeoLocation(accountId,
            lat, lng, geoXSettingName, geoYSettingName);
    assertThat(true, is(updated));
    Account updatedAccount = getAccountById();
    assertThat(Double.parseDouble(updatedAccount.getPremise().getPremiseExtension().get(2).getValue()), is(equals(lat)));
    assertThat(Double.parseDouble(updatedAccount.getPremise().getPremiseExtension().get(3).getValue()), is(equals(lng)));
    //rollback the change
    updatedAccount.getPremise().setPremiseExtension(premiseExtensions);
    updateAccountWithValues(updatedAccount);
}

The method I want to mock is externalApiConfig.getExternalUrl() in following code

public class CisRestBaseService {

protected WebTarget rootWebTarget;
protected ExternalApiConfig externalApiConfig;

public CisRestBaseService() {
    JacksonJsonProvider jacksonJsonProvider = new JacksonJaxbJsonProvider()
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
            .configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, false);

    Client jaxRsClient = ClientBuilder.newClient().register(jacksonJsonProvider);
    this.externalApiConfig = new CisApiConfig();
    this.rootWebTarget = jaxRsClient.target(externalApiConfig.getExternalUrl());
}

}

Any help would be much appreciated.


Solution

  • the problem is that you are not passing the mocked externalApiConfig to the tested class CisRestBaseService. To fix this, you can, for example, define it it as a constructor argument (you can keep the current constructor as well if needed).

    public CisRestBaseService(CisApiConfig config) {
        JacksonJsonProvider jacksonJsonProvider = new JacksonJaxbJsonProvider()
                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                .configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, false);
    
        Client jaxRsClient = ClientBuilder.newClient().register(jacksonJsonProvider);
        this.externalApiConfig = config;
        this.rootWebTarget = jaxRsClient.target(externalApiConfig.getExternalUrl());
    }
    
    public CisRestBaseService() {
        this(new CisApiConfig());
    }
    

    Not, from the test, you can instantiate the service like this:

    Mockito.when(externalApiConfig.getExternalUrl()).thenReturn("http://localhost:8080/serviceURI/");
    cisAccoutService = new CisAccountServiceImpl(externalApiConfig);
    

    As a result, your service under test will use the mock instead of creating a real config object.This technique is called "dependency injection", you can read more about it here: https://www.digitalocean.com/community/tutorials/java-dependency-injection-design-pattern-example-tutorial