You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用RestAssured(spring-mock-mvc)测试Controller时模拟CompletableFuture异常返回失败

问题分析与修复方案

嘿Dan,我一眼就看到两个可能导致测试失败的核心问题,咱们一个个说:

1. 请求参数传递方式不匹配(最直接的原因)

你的RegistrationResource里的register方法用@RequestBody String name接收参数,这意味着接口期望从请求体里读取name的值;但你的测试代码里用了.params("name", "dan")——这是把name作为URL查询参数/表单参数发送,接口根本拿不到正确的参数值,甚至可能触发了非预期的逻辑分支。

你需要把测试里的参数传递改成用请求体:

given()
    .body("dan") // 替换原来的params(),匹配@RequestBody的参数接收方式
    .standaloneSetup(registrationResource)
    .when()
    .post("/players")
    ...

2. Mock服务未正确注入被测资源

你在测试里创建了mockedWhackAMoleService,但如果没有把这个mock实例注入到registrationResource中,被测代码调用的还是真实的whackAMoleService实现,自然不会触发你预设的异常逻辑。

测试方法开头一定要加上mock注入的逻辑:

// 假设你的RegistrationResource有setter方法,或者用构造函数注入
registrationResource.setWhackAMoleService(mockedWhackAMoleService);

修改后的完整测试代码

@Test
public void shouldReturnConflictWhenPlayerAlreadyRegistered() {
    // 关键:将mock服务注入到被测资源实例中
    registrationResource.setWhackAMoleService(mockedWhackAMoleService);
    
    CompletableFuture<Void> failFlow = new CompletableFuture<>();
    failFlow.completeExceptionally(new CompletionException(new PlayerNameAlreadyRegisteredException(
        "Player already registered")));
    when(mockedWhackAMoleService.register(any(String.class))).thenReturn(failFlow);

    given()
        .body("dan") // 用请求体传递参数,匹配@RequestBody
        .standaloneSetup(registrationResource)
        .when()
        .post("/players")
        .then()
        .statusCode(HttpStatus.CONFLICT.value());
}

额外验证小技巧

  • 可以在被测方法register里加个日志打印name的值,确认测试时能正确拿到"dan";
  • 调试时检查registrationResource.whackAMoleService的实例类型,确保是你创建的mock对象而非真实实现。

这样修改后,应该就能正确触发异常分支,返回预期的409状态码了!

内容的提问来源于stack exchange,提问作者danwag

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 09:23:12