Sam
Sam

Reputation: 592

Use Mockito to change values for a method within a method

I want to write a Junit test case that tests the else {id = null; } statement in the code below. What I am trying to do is see if the site is live, if it is then generate an ID, but if it isn't live (or goes down for a bit) to return id as null.

public static String createID() {
    String id = null;
    HttpURLConnection connection = accessProv();
    if (checkConfigs()) {
        try {
            if(checkSiteResponse(connection)) {
                id = generateID(connection);
            } else {
              //test this statement 
                id = null;
            }
        } catch (IOException e) {
          LOG.error("IOException");
        }
    } else {
        id = generateRandomID();
    }
        return id;
}

public static boolean checkConfigs() {
    return (stormConf != null && (boolean)stormConf.get(ENABLE_ID_REGISTRATION) && !((boolean)stormConf.get(SUBMIT_TOPOLOGY_LOCALLY)));

public static HttpURLConnection accessProv() {
    HttpURLConnection connection = null;
    try {
        URL url = new URL(PROV_CREATE_ID_URL);
        connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("GET");
        connection.connect();
        int code = connection.getResponseCode();
    } catch (IOException e) {
        LOG.error("IOException");
    }
    return connection;
}
    public static boolean checkSiteResponse(HttpURLConnection connection) throws IOException {
    Boolean response;
    if (connection.getResponseCode() == 200) {
        response = true;
    } else { response = false; }
    return response;
}

I have written the test case below using Mockito:

@Test
public void testRequestError() throws ParseException, IOException {
    HttpURLConnection mockHttpConnection = Mockito.mock(HttpURLConnection.class);
    ProvenanceUtils provenanceUtils = Mockito.mock(ProvenanceUtils.class);
    provenanceUtils.checkSiteResponse(mockHttpConnection);
    when(provenanceUtils.checkConfigs()).thenReturn(true);
    when(provenanceUtils.accessProvenance().getResponseCode()).thenReturn(100);
    System.out.println(provenanceUtils.createID());

But I get the error:

org.mockito.exceptions.misusing.WrongTypeOfReturnValue: 
Boolean cannot be returned by getResponseCode()
getResponseCode() should return int

I am new to Mockito and can't figure out how to set getResponseCode to be something other than 200. I get the error in the first when statement (when(provenanceUtils.checkConfigs()).thenReturn(true);).

Basically I want checkConfigs() to return true and checkSiteResponse(connection) to return false. Is there a way to do this with Mockito? I wanted to avoid using PowerMock if I can help it.

Upvotes: 1

Views: 685

Answers (2)

Gonzalo Matheu
Gonzalo Matheu

Reputation: 10064

Having in mind that static methods can not be mocked with Mockito unless you use PowerMockito.

Apart from that, what method accessProvenance() returns is not a mock (is an actual HttpURLConnection instance) hence mockito can not modify its behaviour.

You might try mocking http requests using WireMock

@Rule
public WireMockRule wireMockRule = new WireMockRule();

...
public void testRequestError() throws ParseException, IOException {
  stubFor(post(urlEqualTo(PROV_CREATE_ID_URL))
    .willReturn(aResponse()
       .withStatus(100)));
...
}

Upvotes: 1

GhostCat
GhostCat

Reputation: 140427

The problem is that you are pushing way too many responsibilities into one class.

Example: you have a static method checkConfigs(). If you would replace that, with something like

interface ConfigurationChecker() {
  boolean isConfigurationValid();
..

class ConfigurationCheckerImpl implements ...

and then, your class under test contains a field of type ConfigurationChecker; and you use dependency injection (so that your unit tests can push a mocked ConfigurationChecker into your class under test) ... all of a sudden, you gain full control over the elements that influence the behavior of your methods.

In other words: your code, as written right now is simply hard to test. All the elements that you need to control; are simply not (easily) accessible to test code.

You might use Powermock/mockito to still get it tested ... or you step back, learn how to write code that be tested easily (by watching this for example); redo your design ... and end up with something that is A) better designed B) fully testable (without "nasty" workarounds).

Upvotes: 0

Related Questions