java - Mockito 无法模拟 Rest API 调用

标签 java unit-testing mockito

使用 Mockito 测试 REST API,总是出现错误。我试图 mock

apiClient.execute(buildApiCall("POST", url, reqBody), localVarReturnType);

但是没有任何效果,这里的任何帮助将不胜感激

待测系统

public CreateUser createUser(String fullname, String username, String password, String departmentName) {
    String url = "/api/v1/account/?apikey=" + apiKey;
    String randomUsername = generateRandomString(20);
    CreateUser payload = new CreateUser();
    payload.setFullName(fullname);
    payload.setUsername(username);
    payload.setPassword(generatePassword((password != null) ? password : generatePassword(randomUsername)));
    payload.setEmail(username + "@qstack.com");
    payload.setDepartmentName(departmentName);

    RequestBody reqBody = apiClient.serialize(payload, "application/json");
    Type localVarReturnType = new TypeToken<CreateUser>() { }.getType();
    ApiResponse<CreateUser> responseFromApiClient = apiClient.execute(buildApiCall("POST", url, reqBody), localVarReturnType);
    return responseFromApiClient.getData();
}

public Call buildApiCall(String method, String url, RequestBody reqBody) {
    String signature = null;
    try {
        signature = generateSignature(url);
    } catch (SignatureException e) {
        e.printStackTrace();
    }

    return apiCall(method, url, signature, reqBody);
}

private Call apiCall(String method, String url, String signature, RequestBody reqBody) {
    String baseUri = "http://localhost:8002";
    String finalUrl = baseUri + url + "&signature=" + signature;
    final Request.Builder reqBuilder = new Request.Builder().url(finalUrl);
    reqBuilder.header("Accept", "*/*");
    reqBuilder.header("Content-Type", "application/json");

    return httpClient.newCall(reqBuilder.method(method, reqBody).build());
}

单元测试代码

 @Test
public void testQuery() {
    String jsonResponse = "{\n" +
            "    \"address_one\": \"\",\n" +
            "    \"address_three\": \"\",\n" +
            "    \"address_two\": \"\",\n" +
            "    \"country_code\": \"\",\n" +
            "    \"cs_domain_id\": null,\n" +
            "    \"date_joined\": \"2019-10-02T19:12:55.722764\",\n" +
            "    \"disable_personal_account\": false,\n" +
            "    \"email\": \"username123@qstack.com\",\n" +
            "    \"first_name\": \"username123\",\n" +
            "    \"id\": 73,\n" +
            "    \"is_reseller\": false,\n" +
            "    \"is_superuser\": false,\n" +
            "    \"is_verified\": true,\n" +
            "    \"last_login\": null,\n" +
            "    \"last_name\": \"\",\n" +
            "    \"paywall\": true,\n" +
            "    \"postal_code\": \"\",\n" +
            "    \"projects\": [],\n" +
            "    \"reference_number\": \"\",\n" +
            "    \"reseller_id\": 1,\n" +
            "    \"reseller_name\": \"ROOT\",\n" +
            "    \"reseller_rights\": [],\n" +
            "    \"resource_uri\": \"/api/v1/account/73/\",\n" +
            "    \"saml\": false,\n" +
            "    \"state\": 0,\n" +
            "    \"status\": \"enabled\",\n" +
            "    \"surname\": \"\",\n" +
            "    \"username\": \"username123\",\n" +
            "    \"uuid\": \"9f79e45f-9cc8-40e8-b5c6-bd406893bdd6\"\n" +
            "}";

    Gson gson = new GsonBuilder().create();
    CreateUser response = gson.fromJson(jsonResponse, CreateUser.class);
    ApiResponse<CreateUser> responseFromApiClient = new ApiResponse<>(200, null, response);

    OkHttpClient httpClientMock = mock(OkHttpClient.class);
    ApiClient apiClientMock = mock(ApiClient.class);

    when(apiClientMock.serialize(payload, "application/json")).thenReturn(any());
    GqConsoleApiClient g = new GqConsoleApiClient(httpClientMock, apiClientMock);
    Mockito.<ApiResponse<? extends CreateUser>>when(apiClientMock.execute(any(), any())).thenReturn(responseFromApiClient);
    g.createUser("jon", "jon", "jon", "ROOT");

    Assertions.assertEquals("jon", responseFromApiClient.getData().getUsername());
}

在查看 IntelliJ 的覆盖率输出时,我设法到达倒数第二行

ApiResponse responseFromApiClient = apiClient.execute(buildApiCall("POST", url, reqBody), localVarReturnType);

但是测试抛出异常

java.lang.IllegalArgumentException: method POST must have a request body.

at com.squareup.okhttp.Request$Builder.method(Request.java:259)
at com.greenqloud.netappstats.collector.metrics.gqconsole.api.GqConsoleApiClient.apiCall(GqConsoleApiClient.java:136)
at com.greenqloud.netappstats.collector.metrics.gqconsole.api.GqConsoleApiClient.buildApiCall(GqConsoleApiClient.java:126)
at com.greenqloud.netappstats.collector.metrics.gqconsole.api.GqConsoleApiClient.createUser(GqConsoleApiClient.java:82)
at com.greenqloud.netappstats.collector.metrics.gqconsole.api.MockitoTest.testQuery(MockitoTest.java:87)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:513)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:115)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:170)
at org.junit.jupiter.engine.execution.ThrowableCollector.execute(ThrowableCollector.java:40)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:166)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:113)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:58)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:113)
at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$2(HierarchicalTestExecutor.java:121)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177)
at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:121)
at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$2(HierarchicalTestExecutor.java:121)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177)
at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:121)
at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:55)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:43)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:170)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:154)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:90)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:69)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

在添加新的模拟调用后编辑了新错误,请参阅测试函数。

at io.swagger.cv.client.ApiClient.execute(ApiClient.java:840)
at com.greenqloud.netappstats.collector.metrics.gqconsole.api.MockitoTest.testQuery(MockitoTest.java:106)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:513)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:115)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:170)
at org.junit.jupiter.engine.execution.ThrowableCollector.execute(ThrowableCollector.java:40)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:166)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:113)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:58)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:113)
at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$2(HierarchicalTestExecutor.java:121)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177)

这个错误指向这个函数

public <T> ApiResponse<T> execute(Call call, Type returnType) throws ApiException {
    try {
        Response response = call.execute();
        T data = handleResponse(response, returnType);
        return new ApiResponse<T>(response.code(), response.headers().toMultimap(), data);
    } catch (IOException e) {
        throw new ApiException(e);
    }
}

最佳答案

你不是在 mock 这个电话

apiClient.serialize(payload, "application/json");

因此可能返回 null

不要忘记 apiClient 是一个模拟

ApiClient apiClientMock = mock(ApiClient.class);

而且您只是在模拟 execute 方法。

Mockito.<ApiResponse<? extends CreateUser>>when(apiClientMock.execute(any(), any())).thenReturn(responseFromApiClient);

通过模拟 serialize 方法来修复此问题。

关于java - Mockito 无法模拟 Rest API 调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58222458/

相关文章:

java - 如何在抛出异常时在 hibernate 中执行事务

java - 匿名类线程

java - 将 java.time.LocalDate 转换为 java.util.Date 类型

c# - 预期对模拟调用一次,但调用了 2 次 : m => m. SaveChanges() , UnitTest

android - Realm 单元测试

java - 使用 Mockito 测试涉及数据库调用的 Rest API

java - 带有嵌入式 java 的独立 Play 应用程序

unit-testing - 用于测试 vim 插件的工具

java - Powermockito 预期的对象创建在线程中预期时不起作用

python - 如何测试不同格式的日期和日期时间?