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

JUnit测试中如何正确Mock带@Value的Controller构造函数?

问题描述

我有一个需要测试的AccountController,代码如下:

@RestController
@RequestMapping("/api/account")
public class AccountController {

    private final AccountService accountService;

    private UUID correspondentId;


    public AccountController(AccountService accountService, @Value("${app.correspondent}") String correspondentId) {
        this.accountService = accountService;
        this.correspondentId = UUID.fromString(correspondentId);
    }

    @GetMapping("")
    @PreAuthorize("hasRole('CUSTOMER')")
    Mono<String> index(Authentication auth) {
        return.....;
    }
}

我尝试通过以下方式编写测试用例:

@Test
public void testMockUser() {
        AccountService accountService = Mockito.mock(AccountService.class);
        Mockito.mock(AccountController.class, withSettings().useConstructor(accountService, 
        UUID.randomUUID()));

        webTestClient
                .mutateWith(jwtMutator())
                .get().uri("/api/account/")
                .accept(MediaType.APPLICATION_JSON)
                .exchange()
                .expectStatus().isOk();
}

但运行时出现错误:

Caused by: java.lang.IllegalArgumentException: Invalid UUID string: 

请问正确Mock该构造函数参数的方法是什么?


解决方法

错误原因

问题出在构造函数参数类型不匹配:AccountController的构造函数第二个参数是String类型的UUID字符串,但你Mock时传入的是UUID对象,再加上测试环境未加载配置导致实际传入空字符串,触发了UUID.fromString()的非法参数异常。

正确的Mock方式

有两种可行的解决思路:

1. 直接传入合法的UUID字符串

构造函数需要String类型参数,直接生成UUID字符串传入即可:

@Test
public void testMockUser() {
    AccountService accountService = Mockito.mock(AccountService.class);
    // 生成合法的UUID字符串传入构造函数
    String validCorrespondentId = UUID.randomUUID().toString();
    AccountController controller = Mockito.mock(AccountController.class, 
        withSettings().useConstructor(accountService, validCorrespondentId));

    webTestClient
            .mutateWith(jwtMutator())
            .get().uri("/api/account/")
            .accept(MediaType.APPLICATION_JSON)
            .exchange()
            .expectStatus().isOk();
}

注意:要确保Mock的控制器被正确注册到测试上下文,否则请求无法路由到该实例。

2. 利用Spring测试框架注入配置值(推荐)

如果是Spring Boot测试,用@WebFluxTest结合@TestPropertySource直接注入配置值,无需手动处理构造函数:

@WebFluxTest(AccountController.class)
@TestPropertySource(properties = "app.correspondent=550e8400-e29b-41d4-a716-446655440000")
public class AccountControllerTest {

    @Autowired
    private WebTestClient webTestClient;

    @MockBean
    private AccountService accountService;

    @Test
    public void testMockUser() {
        webTestClient
                .mutateWith(jwtMutator())
                .get().uri("/api/account/")
                .accept(MediaType.APPLICATION_JSON)
                .exchange()
                .expectStatus().isOk();
    }
}

这种方式符合Spring测试最佳实践,Spring会自动把配置值注入控制器,无需手动Mock构造函数,代码更简洁。

额外提示

  • 用@MockBean替代手动MockAccountService,Spring会自动管理Mock对象的生命周期,减少冗余代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 02:00:38