Spring Boot+Mockito测试失败:UserService查询返回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

