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

Spring REST Controller单元测试:创建账户时Account始终为null的问题

为啥你的测试里Account总是返回null?我来给你捋清楚

嘿,你的问题其实是Mockito mock对象的典型用法误区,咱们一步步拆解:

核心原因1:Mock的AccountService没设置返回值

你在测试里用mock(AccountService.class)创建了一个模拟的服务对象,但没告诉它当调用createAccount(account)时该返回啥。Mockito的默认规则是:所有mock的方法如果没配置返回值,都会返回null(引用类型)。所以当控制器执行account = accountService.createAccount(account)这行时,拿到的是null,自然最终返回的ResponseEntity里的body就是null了。

核心原因2:Mock的UriComponentsBuilder没处理链式调用

控制器里用到了uriBuilder.path(...).buildAndExpand(...).toUri()这种链式调用,你直接mock了UriComponentsBuilder,但没配置path()方法的返回值——它默认会返回null,后续调用buildAndExpand的时候直接就会抛出空指针异常,这也会导致你的测试逻辑走不下去,甚至可能间接让返回的account变成null。


修复后的测试代码

我给你调整了测试代码,把这两个问题都解决了:

@Test
public void givenValidAccount_whenCreateAccount_thenSuccessed() throws Exception {
    // Arrange
    // 1. 配置AccountService的mock返回值
    AccountService accountService = mock(AccountService.class);
    Account mockSavedAccount = new Account("someone@domain.com");
    mockSavedAccount.setId(1L); // 给返回的Account设置一个有效的ID
    // 告诉mock:不管传入什么Account对象,createAccount都返回我们预设的mockSavedAccount
    when(accountService.createAccount(any(Account.class))).thenReturn(mockSavedAccount);

    // 2. 配置UriComponentsBuilder的链式调用mock
    UriComponentsBuilder uriBuilder = mock(UriComponentsBuilder.class);
    UriComponents uriComponents = mock(UriComponents.class);
    // 链式调用的每一步都要配置返回值,保证调用链不中断
    when(uriBuilder.path(anyString())).thenReturn(uriBuilder);
    when(uriBuilder.buildAndExpand(anyLong())).thenReturn(uriComponents);
    when(uriComponents.toUri()).thenReturn(new URI("/accounts/1"));

    AccountController accountController = new AccountController(accountService);
    Account account = new Account("someone@domain.com");

    // Act
    ResponseEntity<?> createdAccount = accountController.createAccount(account, "", uriBuilder);

    // Assert
    assertNotNull(createdAccount.getBody());
    assertEquals(HttpStatus.CREATED, createdAccount.getStatusCode());
    assertEquals(mockSavedAccount, createdAccount.getBody());
}

额外的小建议

  • 你控制器里的authorizationHeader参数目前没用到,要么在测试里传个合理的值(比如"Bearer test-token"),要么干脆从控制器方法里删掉它,避免不必要的参数干扰。
  • 控制器里判断邮箱非空的逻辑!account.getEmail().equalsIgnoreCase("")可以换成Spring的StringUtils.hasText(account.getEmail()),这样能同时处理空字符串和空白字符串的情况,更严谨。
  • 可以用@Mock注解配合@ExtendWith(MockitoExtension.class)来简化mock对象的创建,让测试代码更清爽。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:43:37