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

Spring Boot+Mockito测试失败:UserService查询返回null如何解决?

解决UserService测试中mockUser返回null的问题

我来帮你分析下测试里mockUser始终为null的核心问题,主要有几个关键错误需要修正:

1. Mockito初始化与依赖注入逻辑错误

你同时用了@RunWith(MockitoJUnitRunner.class)和MockitoAnnotations.initMocks(CentralData.class),而且后者的参数完全不对——initMocks需要传入当前测试类实例(比如this),但其实@RunWith(MockitoJUnitRunner.class)已经会自动初始化所有标注了@Mock和@InjectMocks的字段,完全不需要手动调用这个方法。

另外,你手动new UserService(dataProviderMock)覆盖了@InjectMocks创建的实例,直接废掉了Mockito的自动注入逻辑,这行代码必须删掉,@InjectMocks会自动把dataProviderMock注入到UserService中。

2. Mock行为的顺序完全颠倒

Mockito的核心规则是先定义mock的行为,再调用目标测试方法。你现在是先执行userService.getUserById("testuser"),再设置when(userService.getUser("testuser")).thenReturn(testUser)——这时候方法已经执行完了,mock行为根本没生效,自然返回null。

更重要的是:getUserById是你要测试的方法,不能mock它本身!我们需要mock的是UserService依赖的CentralData的方法,因为UserService的查询逻辑是靠CentralData获取数据的,所以应该针对dataProviderMock的方法设置mock,而非userService自身的方法。

3. Save方法的Mock缺失

在createTestUser里调用了userService.save(testUser),但dataProviderMock的save方法没有被mock,mock对象默认返回null/空操作,导致这个save不会有任何实际效果,后续自然查不到用户。


修正后的完整测试代码

@RunWith(MockitoJUnitRunner.class)
@SpringBootTest(classes = {ApplicationMain.class})
public class UserServiceTest {

    @Mock
    CentralData dataProviderMock;

    @InjectMocks
    private UserService userService;

    private <project>User testUser;

    @Before
    public void init() {
        // 去掉错误的MockitoAnnotations调用,@RunWith已完成mock初始化
        System.out.println("dataProviderMock: " + dataProviderMock);
        System.out.println("userService: " + userService);
        
        testUser = createTestUser();
        // 提前mock数据层的查询方法,匹配UserService的调用逻辑
        when(dataProviderMock.getUserById("testuser")).thenReturn(testUser);
    }

    private <project>User createTestUser() {
        <project>User user = new <project>User();
        user.setSystemId("testuser");
        user.setEmailAddress("testuser@system.com");
        user.setFirstName("Test");
        user.setLastName("User");
        
        // mock数据层的save方法,让save操作返回测试用户
        when(dataProviderMock.save(any(<project>User.class))).thenReturn(user);
        userService.save(user);
        return user;
    }

    @Test
    public void whenUserIdIsProvided_thenRetrievedNameIsCorrect() {
        // 先确保mock行为已定义,再调用要测试的方法
        <project>User mockUser = userService.getUserById("testuser");
        
        // 验证结果(如果User类重写了equals方法,可直接比较对象)
        assertEquals(testUser.getSystemId(), mockUser.getSystemId());
        assertEquals(testUser.getFirstName(), mockUser.getFirstName());
        assertEquals(testUser, mockUser);
    }
}

额外注意事项

  • 如果UserService的getUserById内部调用的是dataProviderMock的其他方法(比如getUser而非getUserById),需要把mock的方法改成对应的when(dataProviderMock.getUser("testuser")).thenReturn(testUser)。
  • 确保User类正确重写了equals和hashCode方法,否则assertEquals(testUser, mockUser)会因为对象引用不同而失败。
  • 若使用Mockito 3.x及以上版本,推荐用@ExtendWith(MockitoExtension.class)代替@RunWith(MockitoJUnitRunner.class),这是JUnit 5的标准写法,兼容性更好。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:56:05