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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 04:40:26