【问题标题】:Mock call and response from a third party API来自第三方 API 的模拟调用和响应
【发布时间】:2019-10-01 13:55:43
【问题描述】:

可以这么说,我正在调用第三方端点。我只是调用端点并解析响应。

public ListUsers listUsers() {
    String url = "/api/v1/account/?apikey=" + apiKey;
    String signature = null;
    try {
        signature = generateSignature(url);
    } catch (SignatureException e) {
        e.printStackTrace();
    }

    Call newCall = apiCall("GET", url, signature, null);

    Type localVarReturnType = new TypeToken<ListUsers>() { }.getType();
    ApiResponse<ListUsers> responseFromApiClient = apiClient.execute(newCall, localVarReturnType);
    return responseFromApiClient.getData();
}

listUsers() 函数已被重构以获得更好的抽象

public ListUsers listUsers() {
    String url = "/api/v1/account/?apikey=" + apiKey;
    Type localVarReturnType = new TypeToken<ListUsers>() { }.getType();
    ApiResponse<ListUsers> responseFromApiClient = apiClient.execute(buildApiCall("GET", url, null), localVarReturnType);
    return responseFromApiClient.getData();
}

这个特定的端点不接受任何正文,并返回我然后解析的 json。

{
    "meta": {
        "limit": 0,
        "offset": 0,
        "total_count": 1
    },
    "objects": [
        {
            "address_one": "",
            "address_three": "",
            "address_two": "",
            "country_code": "",
            "cs_domain_id": null,
            "date_joined": "2019-07-05T13:50:21",
            "disable_personal_account": false,
            "email": "noreply@some.com",
            "first_name": "",
            "id": 1,
            "is_reseller": true,
            "is_superuser": true,
            "is_verified": true,
            "last_login": null,
            "last_name": "",
            "paywall": true,
            "postal_code": "",
            "projects": [],
            "reference_number": "",
            "reseller_id": 1,
            "reseller_name": "ROOT",
            "reseller_rights": [
                {
                    "domain_id": null,
                    "id": 1,
                    "level": "owner",
                    "name": "ROOT"
                }
            ],
            "resource_uri": "/api/v1/account/1/",
            "saml": false,
            "state": 0,
            "status": "enabled",
            "surname": "",
            "username": "admin",
            "uuid": "1c208540-3ed9-4741-a936-a574a3ded12a"
        }
    ]
}

然后解析这个 json 响应。

我如何为此编写适当的单元测试,还是不需要它?我想出的唯一测试只是我实际调用服务的基本测试,但至于纯单元测试,它不适用于我的构建服务器。这是测试

@Test
void getListProjectsTest() {
    GqConsoleApiClient gcac = new GqConsoleApiClient();
    ListProjects response = gcac.listProjects();
    System.out.println(listProjects);
    Assert.assertEquals(20, response.getMeta().getLimit());
    Assert.assertEquals("some-customer-id", response.getObjects().get(0).getCustomerId());
}

【问题讨论】:

    标签: java rest unit-testing mocking mockito


    【解决方案1】:

    有多种方法可以做到这一点。如果我是你,我会这样做

    1. 首先创建一个带有正确响应的json文件

    2. 编写一个测试用例,其中

      2.1。加载测试类中的json文件

      File sampleFile = new File(URLDecoder.decode(classLoader.getResource("jsonFilePath").getFile(), "UTF-8"));  
      

      2.2 将此文件转换为java类型,该类型将从第三方API返回。在您的情况下,它是ApiResponse&lt;ListUsers&gt;。为此,您可以使用 Jackson 或 Gson 库

      2.3 您应该创建一个 apiClient 类型的模拟并模拟 execute 调用。并返回从步骤 2.2 得到的 java 对象。像这样的

      when(apiClient.execute(any(), any()).thenReturn(....)  
      

      2.4 编写断言检查java对象的各个方面

    这样您可以轻松创建多个 json 文件来测试来自 api 的各种响应。

    【讨论】:

      【解决方案2】:

      我如何为此编写适当的单元测试,还是不需要它?

      在单元测试方面,您的逻辑非常简洁。
      您调用 API:

      ApiResponse<ListUsers> responseFromApiClient = apiClient.execute(newCall, localVarReturnType);
      

      在下一条语句中:

      return responseFromApiClient.getData();
      

      您只需返回getData()

      因此,就单元测试而言,您需要使用任何ApiResponse&lt;ListUsers&gt; 对象模拟execute() 的返回,并断言您从该对象返回getData()

      类似的东西:

      // GIVEN
      ApiResponse<ListUsers> responseFromApiClientByMock = Mockito.any();
      Data dataByMock = Mockito.when(responseFromApiClientByMock.getData()).thenReturn(Mockito.mock(Data.class);
      Mockito.when(apiClientMock.execute(newCall, localVarReturnType)).thenReturn(responseFromApiClientByMock);
      // WHEN
      Data actualData = foo.listUsers();
      // THEN
      Assertions.assertSame(dataByMock, actualData);
      

      当然,要测试的那种组件会产生非常浅的单元测试。
      因此,您应该明确地为listUsers() 方法或更高级别的方法创建集成测试,因为您不想在每一层中重复集成测试逻辑。

      您可以参考 pvpkiran 答案,该答案很好地解决了集成测试问题,并使其从正确的级别开始:listUsers() 或更高。

      【讨论】:

      • 感谢您的回复,但是对于rest api的纯单元测试,它本身可能没有多大价值,但另一方面集成测试有很大帮助。
      • 不客气。那是肯定的。请注意,该测试并不是那么无用。假设有人更改了listUsers() 方法,其中数据是从另一个字段或源错误地检索而不是getData(),通过该测试,您现在可以检测到这一点。而且该测试在维护方面相当稳定。
      猜你喜欢
      • 2015-05-15
      • 2016-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多