zappee
zappee

Reputation: 22646

How to test a method which requires an external rest call?

I would like to unit test a method which logs in the user via an external access management infrastructure. I do not know how to mock the Response response object.

This is my code what I intend to test:

public String login(final String username, final String password) {
    String baseUrl = getOpenAMApiBaseUrl();
    String path = "/openam/json/authenticate";

    // Response NEEDS TO BE MOCKED SOMEHOW
    Response response = jaxClient.target(baseUrl + path)
            .request(MediaType.APPLICATION_JSON_TYPE)
            .header(HttpHeaderField.OPENAM_USERNAME, username)
            .header(HttpHeaderField.OPENAM_PASSWORD, password)
            .post(Entity.json(null));

    int status = response.getStatus();
    String jsonResponse = response.readEntity(String.class);

    if (status == Response.Status.OK.getStatusCode()) {
        try (JsonReader jsonReader = Json.createReader(new StringReader(jsonResponse))) {
            JsonObject jsonObject = jsonReader.readObject();
            String token = jsonObject.getString("tokenId");
            LOGGER.info("{} have successfully logged in", username);
            return token;
        } catch (NullPointerException e) {
            LOGGER.info("login failed, invalid json response for {}/{}", username, password);
            return null;
        }
    }

    String message = "an error occurred during logging in, http status: {}, user: {}/{}";
    if (status == Response.Status.UNAUTHORIZED.getStatusCode()) {
        message = "invalid credentials, http status: {}, user: {}/{}";
    }
    LOGGER.info(message, status, username, password);
    return null;
}

Upvotes: 1

Views: 386

Answers (1)

Maciej Kowalski
Maciej Kowalski

Reputation: 26492

Well ideally you would have to mock all the call starting from the jaxClient.target method but in this case due to a very long chain needed to produce a mock i would suggest one of two options:

1) (preferrable) - extract the creation of the Response to a new class that specializes only in that particular operation.

Then you would declare that class as the dependency of the class under test an simply inject a mock of it with the builder method configured to return a certain Response object.

2) You can create a package level method in your class like following:

Response buildResponse(){
    String baseUrl = getOpenAMApiBaseUrl();
    String path = "/openam/json/authenticate";

    // Response NEEDS TO BE MOCKED SOMEHOW
    Response response = jaxClient.target(baseUrl + path)
            .request(MediaType.APPLICATION_JSON_TYPE)
            .header(HttpHeaderField.OPENAM_USERNAME, username)
            .header(HttpHeaderField.OPENAM_PASSWORD, password)
            .post(Entity.json(null));
}

Then @Spy your class under test and mock that method to return a Response that you desire:

@Spy
ClassUnderTest classUnderTest;

@Mock
Response responseMock;

@Before
public void init(){
    MockitoAnnotations.initMocks(this);
}

@Test
public void test(){
    doReturn(responseMock).when(classUnderTest).buildResponse();

    // Act

    classUnderTest.login(login,pass);

   // Assertions
}

Upvotes: 2

Related Questions