Nags
Nags

Reputation: 283

How to write Junit test case for postAbs method of WebClient in Vert.x?

I recently developed few Verticles from which I needed to make external API calls. To optimize the code, I moved code of calling APIs to one common Helper class. I am also passing Vertx instance from Verticle to Helper class. I am now trying to write Junit test case for the Helper class which is looking like below working code.

public class ServiceExecutionHelper{

public Promise<String> executeService(String requestURI, JsonObject input, MultiMap headers, Vertx vertx){
        Promise<String> promise = Promise.promise();
        WebClient client = WebClient.create(vertx);
        client.postAbs(requestURI).timeout(60000).putHeaders(headers)
        .sendJsonObject(input, ar -> {
            if (ar.succeeded()) {
                HttpResponse<Buffer> response = ar.result();
                JsonObject serviceRespone = new JsonObject(response.bodyAsString());
                JsonArray responseData = serviceRespone.getJsonArray("response_data");
                if(responseData != null){
                    promise.complete("promise_completed");
                }else{
                    promise.fail("promise_failed");
                }
            }
        }
        return promise;
}
}

Can anyone please guide how could I write test case for above code?

Upvotes: 1

Views: 1529

Answers (1)

Erunafailaro
Erunafailaro

Reputation: 1959

There are a million ways to do this depending on what exactly you need to test.

Here is one suggestion using junit5 and okhttp's MockWebServer. There are a lot of other conceivable alternatives.

The test verifies:

  • That you send a POST request using the payload contained in the input parameter.
  • That your implementation can handle a json response from the webserver.
  • That your implementation sends exactly one request to the webserver.
  • That your code completes the Promise if the server's response contains the key "promise_completed"
    @ExtendWith(VertxExtension.class)
    @Slf4j
    public class ServiceExecutionHelperTest {

        private ServiceExecutionHelper sut;

        private MockWebServer mockWebServer;

        @BeforeEach
        public void setUp() {
            sut = new ServiceExecutionHelper();
            mockWebServer = new MockWebServer();
        }

        @Test
        public void testExecuteService(final Vertx vertx, final VertxTestContext testContext) throws InterruptedException {
            // given
            final JsonObject requestPayload = new JsonObject().put("request", new JsonArray("[]"));
            final JsonObject serverResponsePayload = new JsonObject().put("response_data", new JsonArray("[]"));
            mockWebServer.enqueue(new MockResponse()
                                      .setBody(serverResponsePayload.encode())
                                      .setResponseCode(200)
                                      .setHeader("content-type", "application/json"));

            // when
            final Promise<String> stringPromise =
                sut.executeService(
                    mockWebServer.url("/").toString(),
                    requestPayload,
                    MultiMap.caseInsensitiveMultiMap(),
                    vertx);

            // then
            final RecordedRequest recordedRequest = mockWebServer.takeRequest();
            assertEquals("POST", recordedRequest.getMethod());
            assertEquals("[text={\"request\":[]}]", recordedRequest.getBody().toString());
            assertEquals(1, mockWebServer.getRequestCount());
            testContext.assertComplete(stringPromise.future())
                       .map(val -> {
                           assertEquals("promise_completed", val);
                           testContext.completeNow();
                           return val;
                       })
                       .onComplete(onComplete -> {
                           assertTrue(onComplete.succeeded());
                           log.info("done");
                       })
                       .onFailure(onError -> Assertions.fail());

        }
    }

Some words from a TDD point of view

Before you start writing tests (and your actual code too, if you ask me), you should clarify your functional and technical requirements.

These should be the basis for your tests. And the tests should be a starting point to implement your code against.

So I cannot promise you that this example is a correct test for your use case. It compiles and and runs. But it should be verified and extended following your actual requirements.

Concerning test coverage

To keep this answer short and concise, I did not write the test to cover all possible branches. The case where the server responds without response_data (i.e. the else branch of your if-clause, where the Promise fails) is not tested.

To cover that case, a second test or the usage of a parameterized test would be necessary.

Upvotes: 1

Related Questions