java - 如何为 MockServer 的相同请求设置不同的响应?

标签 java spring unit-testing spring-boot-test mockserver

我在为具有完全相同请求的多个响应设置 MockServerClient 时遇到问题。

我读到,如果对“Times”抱有期望,这可能会完成,但我无法使其适用于我的场景。

如果您使用此 JSON 调用服务(两次):

{
    "id": 1
}

第一个响应应该是“passed true”,第二个响应应该是“passed false”

响应 1:

{
    "passed":true
}

响应 2:

{
    "passed":false
}

我设置了第一个请求,但如何设置第二个请求?

import com.nice.project.MyService;
import com.nice.project.MyPojo;
import org.mockito.Mock;
import org.mockserver.integration.ClientAndServer;
import org.mockserver.matchers.TimeToLive;
import org.mockserver.matchers.Times;
import org.mockserver.model.Header;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.test.context.TestPropertySource;

import java.io.File;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.contains;
import static org.mockito.Mockito.when;
import static org.mockserver.integration.ClientAndServer.startClientAndServer;
import static org.mockserver.model.HttpRequest.request;
import static org.mockserver.model.HttpResponse.response;

@SpringBootTest    
public class Tests{
    
    private static final int PORT = 9998;

    private static ClientAndServer mockServer;

    @Autowired
    private MyService myService;

    @BeforeAll
    public void init(){
        mockServer = startClientAndServer(PORT);
        mockServer
            .when(
                request()
                    .withPath(testUrlValidateTransactionOk).withMethod(HttpMethod.POST.name())
                    .withHeaders(
                        new Header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON.toString())
                    )
                    .withBody(contains("\"id\":\"1\""))
                ).respond(
            response().withStatusCode(HttpStatus.OK.value())
                .withHeaders(
                    new Header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON.toString())
                )
                .withBody("{\"passed\":true}"));

        // What do i set here? Or in the snippet before by chaining?
        // mockServer.when()...

    }

    @Test
    void t1{
        //myService will internally call the MockServer

        //FIRST CALL -> Pass
        MyPojo p = myService.call(1);

        assertThat(p.isPassed()).isEqualTo(Boolean.TRUE);

        //SECOND CALL -> No Pass
        MyPojo p2 = myService.call(1);
        assertThat(p2.isPassed()).isEqualTo(Boolean.FALSE);

    }
}

依赖关系(相关):

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.4</version>
    </parent>

    <groupId>com.nice.project</groupId>
    <artifactId>testing</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>test</name>
    <description>Testing</description>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <httpclient.version>4.5.13</httpclient.version>
        <mock-server.version>5.11.2</mock-server.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>   
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>               
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-json</artifactId>
        </dependency>   
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>   
        
        <!--HTTP CLIENT-->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
        </dependency>
        
        <!--TEST-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mock-server</groupId>
            <artifactId>mockserver-netty</artifactId>
            <version>${mock-server.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mock-server</groupId>
            <artifactId>mockserver-client-java</artifactId>
            <version>${mock-server.version}</version>
            <scope>test</scope>
        </dependency>       

    </dependencies>

</project>

提前谢谢你。

最佳答案

在关注并深入研究文档和测试之后。

我发现您可以指定一个“Times”来匹配预期 完美解决了我的问题。

链接:https://www.mock-server.com/mock_server/creating_expectations.html

对于每个期望,我都使用“Times.exactly(1)”。

它的工作方式是在匹配时将期望添加到列表中 它将被消耗,并从列表中删除,留下下面的。

如果没有找到调用预期,它将从模拟服务器返回一个404

文档示例链接: https://www.mock-server.com/mock_server/creating_expectations.html#button_match_request_by_path_exactly_twice

正确的代码:

//The first call will land here, and then this expectation will be deleted, remaining the next one
mockServer
.when(
    request()
        .withPath(testUrlValidateTransactionOk).withMethod(HttpMethod.POST.name())
        .withHeaders(
            new Header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON.toString())
        )
        .withBody(
            json("{\"id\":1}",
                MatchType.ONLY_MATCHING_FIELDS)),
        Times.exactly(1)
    ).respond(
response().withStatusCode(HttpStatus.OK.value())
    .withHeaders(
        new Header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON.toString())
    )
    .withBody("{\"passed\":true}"));


//After the first call this will be consumed and removed, leaving no expectations
mockServer
.when(
    request()
        .withPath(testUrlValidateTransactionOk).withMethod(HttpMethod.POST.name())
        .withHeaders(
            new Header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON.toString())
        )
        .withBody(
            json("{\"id\":1}",
                MatchType.ONLY_MATCHING_FIELDS)),
        Times.exactly(1)
    ).respond(
response().withStatusCode(HttpStatus.OK.value())
    .withHeaders(
        new Header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON.toString())
    )
    .withBody("{\"passed\":false}"));

关于java - 如何为 MockServer 的相同请求设置不同的响应?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67091263/

相关文章:

java - jQuery js 文件未加载

unit-testing - 计数断言

c# - 如何在单元测试中使用 AutoData 在测试参数中提供一个类型的 N 个对象?

java - 方法命名中的 Spring 'NOT IN' 未按预期工作

java - Hibernate 模块错误 OGM + MongoDB 和 Wildfly 10

java - Maven 部署目标失败

json - @ResponseBody 不使用 Hibernate Call 生成 json

unit-testing - 运行所有 zend framework2 单元测试

java - Mongodb java 驱动程序将结果作为字符串而不是 bson 对象获取

java - 将 2d double 数组转换为 2d int 数组