wiremocking Spring Boot Service POST 方法时出现 WebClientRequestException

问题描述 投票:0回答:1

我正在 Spring Boot 中测试我的服务,但我得到了

WebClientRequestException: failed to resolve 'null' after 6 queries; nested exception is java.net.UnknownHostException: failed to resolve 'null' after 6 queries.

总的来说,我对模拟和测试很陌生。我猜存根是正确完成的,但断言是错误完成的。这是我的服务:

public String changeState(String ids) {
    MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
    form.add("ids", ids);

return webClient.post()
        .uri("/vobjects/ecotox_study__c/actions/Objectlifecyclestateuseraction.ecotox_study__c.study_setup_completed_state__c.change_state_to_study_contracted_useract__c")
        .header(HttpHeaders.AUTHORIZATION, getSessionId())
        .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
        .bodyValue(form)
        .retrieve()
        .bodyToMono(String.class)
        .block();
}

这是我的测试,以邮递员的响应为主体:

@Test
@DisplayName("Test changeState")
void changeState() {
    String body = "{\n" +
            "    \"responseStatus\": \"SUCCESS\",\n" +
            "    \"data\": [\n" +
            "        {\n" +
            "            \"responseStatus\": \"SUCCESS\",\n" +
            "                \"id\": \"V4600000001K001\",\n" +
            "        }\n" +
            "    ]\n" +
            "}";
    wireMockServer.stubFor(post(urlEqualTo("/api/v21.3/vobjects/ecotox_study__c/actions/Objectlifecyclestateuseraction.ecotox_study__c.study_setup_completed_state__c.change_state_to_study_contracted_useract__c"))
            .willReturn(aResponse()
                    .withStatus(200)
                    .withHeader("Content-Type", "application/json")
                    .withBody(body))
    );
    String vaultIds = vaultServiceTest.changeState("V4600000001K001");
    assertEquals(body, vaultIds);
}

正如我所见,断言显然是错误的,因为我断言的是整个主体而不是单个字符串。我不确定这是正确的方法还是我的测试方法整体上是错误的。

java spring-boot junit5 wiremock
1个回答
0
投票

WebClientRequestException:6 次查询后未能解析“null”;

此错误消息表明,在运行测试时,正在使用

WebClient
基本 URL 创建
null
。不确定如何在实际代码中创建
WebClient
,但一种也可以在测试中实现此功能的方法是在测试类中创建一个以
localhost
作为基本 URL 的方法,以便它可以与WireMock。

例如:

@Test
@DisplayName("Test changeState")
void changeState() {
    //Create and start the WireMockServer for localhost on port 8090
    WireMockServer wireMockServer = new WireMockServer(8090);
    wireMockServer.start();

    //Create a WebClient with base URL localhost on port 8090
    WebClient localhostWebClient = WebClient.builder().baseUrl("http://localhost:8090").build();

    //Initialize VaultService with the localhost web client
    VaultService vaultService = new VaultService(localhostWebClient);

    ...

要允许将

WebClient
注入 Vault 服务,请在构造函数中为
WebClient
添加参数:

public class VaultService {

    private WebClient webClient;

    public VaultService(WebClient webClient) {
        this.webClient = webClient;
    }
    ...

正如我所见,断言显然是错误的,因为我断言的是整个主体而不是单个字符串。

假设字段名称和数据类型匹配,并且 JSON 在语法上有效,则可以将 JSON 响应映射到 Java 对象。以下是一些可以与 JSON 响应的数据模型相匹配的 Java 对象:

VaultResponse.java

public class VaultResponse {
    private String responseStatus;
    private VaultResponseData[] data;

    public String getResponseStatus() {
        return responseStatus;
    }

    public void setResponseStatus(String responseStatus) {
        this.responseStatus = responseStatus;
    }

    public VaultResponseData[] getData() {
        return data;
    }

    public void setData(VaultResponseData[] data) {
        this.data = data;
    }
}

VaultResponseData.java

public class VaultResponseData {
    private String responseStatus;
    private String id;

    public String getResponseStatus() {
        return responseStatus;
    }

    public void setResponseStatus(String responseStatus) {
        this.responseStatus = responseStatus;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}

现在在

changeState()
方法中,响应可以映射到
VaultResponse
对象而不是
String
:

return webClient.post()
        .uri("/vobjects/ecotox_study__c/actions/Objectlifecyclestateuseraction.ecotox_study__c.study_setup_completed_state__c.change_state_to_study_contracted_useract__c")
        .header(HttpHeaders.AUTHORIZATION, getSessionId())
        .header(HttpHeaders.ACCEPT, PageAttributes.MediaType.APPLICATION_JSON_VALUE)
        .bodyValue(form)
        .retrieve()
        .bodyToMono(VaultResponse.class) //Response can be mapped to an Object instead of a raw String
        .block();

最后,在断言中,您可以仅对 ID 字符串而不是整个 JSON 响应正文进行断言。有几件事也必须解决:

  1. JSON 正文中的 ID 后面有一个额外的逗号。
    \"id\": \"V4600000001K001\",\n"
    应该变成
    \"id\": \"V4600000001K001\"\n"
  2. WireMock URL 应与代码中使用的 URL 匹配。

这是所有更改后的整个测试方法:

@Test
@DisplayName("Test changeState")
void changeState() {
    //Create and start the WireMockServer for localhost on port 8090
    WireMockServer wireMockServer = new WireMockServer(8090);
    wireMockServer.start();

    //Create a WebClient with base URL localhost on port 8090
    WebClient localhostWebClient = WebClient.builder().baseUrl("http://localhost:8090").build();

    //Initialize VaultService with the localhost web client
    VaultService vaultService = new VaultService(localhostWebClient);

    String body = "{\n" +
            "    \"responseStatus\": \"SUCCESS\",\n" +
            "    \"data\": [\n" +
            "        {\n" +
            "            \"responseStatus\": \"SUCCESS\",\n" +
            "                \"id\": \"V4600000001K001\"\n" + //Extra comma here was removed to make this valid JSON
            "        }\n" +
            "    ]\n" +
            "}";

    //This URL must match the URL being called in the code
    wireMockServer.stubFor(post(urlEqualTo("/vobjects/ecotox_study__c/actions/Objectlifecyclestateuseraction.ecotox_study__c.study_setup_completed_state__c.change_state_to_study_contracted_useract__c"))
            .willReturn(aResponse()
                    .withStatus(200)
                    .withHeader("Content-Type", "application/json")
                    .withBody(body))
    );

    VaultResponse vaultResponse = vaultService.changeState("V4600000001K001");
    assertEquals("V4600000001K001", vaultResponse.getData()[0].getId());
}
© www.soinside.com 2019 - 2024. All rights reserved.