使用 MockServer 的 Wiremock 返回模拟的 http 响应时尝试更新嵌入式数据库

Posted

技术标签:

【中文标题】使用 MockServer 的 Wiremock 返回模拟的 http 响应时尝试更新嵌入式数据库【英文标题】:Trying to update embedded database when mocked http response is returned using Wiremock of MockServer 【发布时间】:2021-09-09 01:08:43 【问题描述】:

在 Spring Boot 上下文中工作,我正在测试一个查询数据库的服务,然后进行远程调用以更新数据库,然后重新查询数据库以获取更新的数据。

我正在尝试使用 Wiremock 或 MockServer 来模拟远程调用,但不知道如何在模拟服务器响应生成过程中更新嵌入式数据库。

例如,使用 MockServer,我尝试创建一个具有自动装配 JdbcTemplate 实例的回调类,但在回调的上下文中 JdbcTemplate 变量为空。

    public class ApprovalHappyPathCallback implements ExpectationResponseCallback 
    JdbcTemplate jdbcTemplate;

    @Autowired
    public void setDataSource(DataSource ds) 
        jdbcTemplate = new JdbcTemplate(ds);
    

    public static final HttpResponse httpResponse = response()
            .withStatusCode(HttpStatusCode.ACCEPTED_202.code())
            .withHeaders(
                    header("x-callback", "test_callback_header"),
                    header("Content-Length", "a_callback_response".getBytes(UTF_8).length),
                    header("Connection", "keep-alive")
            )
            .withBody("a_callback_response");

    @Override
    public HttpResponse handle(HttpRequest httpRequest) 
        if (httpRequest.getMethod().equals("GET")) 
            jdbcTemplate.execute("update communications set status = 'APPROVED_SCHEDULED' where id = 153511");
            return httpResponse;
         else 
            return notFoundResponse();
        
    

回调执行,但 jdbcTemplate 语句不起作用。

在测试中回调是这样引用的:

mockServer.when(request().withMethod("GET"))
        .withBody("Approved")
        // );
        .respond(
            callback()
                .withCallbackClass(ApprovalHappyPathCallback.class)
        );

进行远程调用的服务方法本质上是:

public CommunicationEntity approveCommunication(Long communicationId) 
    String approvalToken = commRepo.approvalTokenById(communicationId);
        if (approvalToken == null) 
            approvalToken = UUID.randomUUID().toString();
            communicationEntity.setApprovalToken(approvalToken);
            commRepo.save(communicationEntity);
        
    String approvalResponse = remoteCommunicationApprover.approveCommunication(communicationId, approvalToken);
    CommunicationEntity communicationEntity = getCommunicationById(communicationId);

        if (communicationEntity.getStatus() != CommunicationStatus.Approved_Scheduled) 
            throw new BadRequestException(
                    "Approval request for communication " + communicationId + " and token " + approvalToken
                            + " failed with remote response: " + approvalResponse,
                    ErrorCodes.COMMUNICATION_SVC_REMOTE_APPROVAL_REQUEST_FAILED);
        
        return communicationEntity;


【问题讨论】:

ApprovalHappyPathCallback 是 Spring 托管的 Bean 吗? 【参考方案1】:

有两个问题导致问题:确保回调方法中使用的 jdbcTemplate 配置了正确的 DataSource,并确保嵌入式内存数据库中的数据可以从 MockServer 响应生成线程访问。

我通过对 MockServer 回调使用 lambda 或闭包解决了第一个问题,其中我使用在测试类中创建的 JdbcTemplate 实例和自动装配的 DataSource(尽管回调类方法也存在解决方案)。

第二个问题是测试方法在事务中的结果,因此当 MockServer 线程(请注意,MockServer 响应生成发生在与运行测试方法的主线程不同的线程)正在执行回调。因此,回调无法访问这些插入。

解决方案是使用 @Transactional(propagation = Propagation.NOT_SUPPORTED) 注释测试方法 见h2 database access to test data from separate threads

【讨论】:

以上是关于使用 MockServer 的 Wiremock 返回模拟的 http 响应时尝试更新嵌入式数据库的主要内容,如果未能解决你的问题,请参考以下文章

(07)使用WireMock快速伪造REST服务

(07)使用WireMock快速伪造REST服务

在春季启动测试中使用wiremock随机端口设置属性

使用WireMock伪造REST服务

WireMock中的SOAP附件

在Java中使用WireMock和SOAP Web服务