Mock控制器调用Service方法返回Null,单元测试问题排查
问题根源与解决方案
核心问题
你在测试类里给UserService标注了@Mock,这会让Mockito创建一个模拟对象,而非真实的UserServiceImpl实例。Controller调用的是这个Mock版的service,它的getUserProps()方法默认返回null,而且永远不会执行真实类里的逻辑——不管你怎么MockUserCache都没用,因为真实的Service代码根本没被调用到。
解决方案分两种场景
场景1:想要测试Controller+真实Service的完整逻辑
需要让Controller使用真实的UserServiceImpl实例,同时Mock它的依赖UserCache:
@ExtendWith(MockitoExtension.class) // JUnit 5 注解,JUnit 4用@RunWith(MockitoJUnitRunner.class) public class ControllerTest { @InjectMocks UserController userController; @Spy // 用Spy包装真实的Service实例 UserServiceImpl userService = new UserServiceImpl(); @Mock UserCache userCache; @BeforeEach void setUp() { // 把Mock的userCache注入到真实的service中 ReflectionTestUtils.setField(userService, "userCache", userCache); } @Test void testGettingUserProps() { // 先模拟userCache的返回数据 Map<String, CacheResult> mockCacheData = new HashMap<>(); mockCacheData.put("user_001", new CacheResult("name", "张三")); // 按你的CacheResult结构构造测试数据 Mockito.when(userCache.asMap()).thenReturn(mockCacheData); // 调用Controller方法 ResponseEntity<Object> result = userController.getAllUserProps(); // 断言结果非空,且符合预期 Assertions.assertNotNull(result); // 补充其他业务断言,比如返回的Map包含预期的键值对 } }
场景2:只测试Controller的逻辑(不关心Service内部)
直接MockUserService的getUserProps()方法即可,无需管UserCache:
@ExtendWith(MockitoExtension.class) public class ControllerTest { @InjectMocks UserController userController; @Mock UserService userService; @Test void testGettingUserProps() { // 模拟Service的返回结果 Map<String, Object> mockUserProps = new HashMap<>(); mockUserProps.put("username", "张三"); mockUserProps.put("role", "admin"); Mockito.when(userService.getUserProps()).thenReturn(mockUserProps); // 调用Controller方法 ResponseEntity<Object> result = userController.getAllUserProps(); // 断言结果 Assertions.assertNotNull(result); Assertions.assertEquals(mockUserProps, result.getBody()); } }
额外注意
- 确保测试类上添加了Mockito的扩展注解(如
@ExtendWith(MockitoExtension.class)),否则Mock对象不会被正确初始化。 - 如果用的是Spring Boot的测试框架,也可以用
@MockBean替代@Mock,但纯单元测试用Mockito原生注解更轻量。
内容的提问来源于stack exchange,提问作者Dan
相关产品推荐
相关产品推荐

