1

我最近开发了一些需要从中进行外部 API 调用的 Verticle。为了优化代码,我将调用 API 的代码移到了一个常见的 Helper 类中。我还将 Vertx 实例从 Verticle 传递给 Helper 类。我现在正在尝试为 Helper 类编写 Junit 测试用例,它看起来像下面的工作代码。

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;
}
}

谁能指导我如何为上述代码编写测试用例?

4

1 回答 1

1

根据您需要测试的具体内容,有上百万种方法可以做到这一点。

这是使用 junit5 和 okhttp 的MockWebServer的一个建议。还有很多其他可以想象的替代方案。

测试验证:

  • 您使用输入参数中包含的有效负载发送 POST 请求。
  • 您的实现可以处理来自网络服务器的 json 响应。
  • 您的实现仅向网络服务器发送一个请求。
  • Promise如果服务器的响应包含密钥,则您的代码完成"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());

        }
    }

从 TDD 的角度来看的话

在你开始编写测试(以及你的实际代码,如果你问我的话)之前,你应该明确你的功能和技术要求。

这些应该是您测试的基础。测试应该是实现代码的起点。

所以我不能保证这个例子是对你的用例的正确测试。它编译并运行。但应根据您的实际要求对其进行验证和扩展。

关于测试覆盖率

为了使这个答案简洁明了,我没有编写测试来涵盖所有可能的分支。服务器没有响应的情况response_data(即else你的 if 子句的分支,Promise 失败的地方)没有经过测试。

为了涵盖这种情况,需要进行第二次测试或使用参数化测试。

于 2020-01-14T14:10:36.090 回答