使用JUnit与Mockito测试Controller的方式是否正确?求正确单元测试方法
JUnit+Mockito测试Controller的正确性验证与优化指导
问题背景
作为单元测试新手,我使用JUnit和Mockito测试Controller类时,对当前的测试方式存疑:Controller中调用Service的isNull方法判断参数是否为空,测试中Mock了Service类,让isNull返回true,不确定这种做法是否正确,希望得到澄清和正确的测试方法指导。
现有代码
Controller类
public class MyClass { @Autowired private MyService myservice; @PostMapping("/sendNotificationToUsers") public ResponseEntity<?> myFunction(@RequestBody MyModelClass myModelClass, HttpServletRequest request) { if (myservice.isNull(myModelClass.getPID())) { logging.error(ErrorMessages.ErrorLogs.NULL_PID.getMessage()); throw new CustomException(ErrorCodes.NULL_PID); } // 其他业务逻辑省略 } }
Service类
public class MyService { public boolean isNull(String str) { return str == null; } }
测试类
@SpringBootTest public MyTestClass { @InjectMocks private MyClass myClass; @Mock private MyService myservice; private final MockHttpServletRequest request = new MockHttpServletRequest(); @Test public void nullPidTest() { MyModelClass myModelClass = new MyModelClass(); myModelClass.setPID(null); when(myservice.isNull(myModelClass.getPID())).thenReturn(true); try { myClass.myFunction(myModelClass, request); } catch (CustomException e) { assertTrue(e.getMessage().contains(ErrorCodes.NULL_PID)); } } }
分析与优化建议
1. 当前测试的合理性判断
你Mock Service的isNull方法来验证Controller逻辑的思路是正确的:单元测试Controller的核心是隔离依赖(这里的Service就是依赖),只验证Controller自身的业务逻辑——当Service返回true时,是否会抛出指定的CustomException。
2. 测试代码的优化点
(1)替换过重的测试注解
@SpringBootTest会启动完整的Spring应用上下文,对于Controller单元测试来说冗余且耗时。应该使用@WebMvcTest,它只会加载Controller相关的Bean,测试更轻量:
@WebMvcTest(MyClass.class) public class MyTestClass { // ... }
(2)使用Spring测试环境的Mock注入方式
在@WebMvcTest环境下,推荐用@MockBean来注入Mock的Service,它会自动将Mock对象放入Spring上下文,供Controller依赖注入,替代@InjectMocks+@Mock的组合:
@WebMvcTest(MyClass.class) public class MyTestClass { @Autowired private MockMvc mockMvc; @MockBean private MyService myservice; // ... }
(3)简化异常断言逻辑
JUnit 5提供了assertThrows方法,可以更简洁地断言异常,替代繁琐的try-catch:
@Test public void nullPidTest() { MyModelClass myModelClass = new MyModelClass(); myModelClass.setPID(null); // 当传入null时,Mock Service返回true when(myservice.isNull(anyString())).thenReturn(true); // 直接断言抛出的异常类型和错误码 CustomException exception = assertThrows(CustomException.class, () -> { myClass.myFunction(myModelClass, new MockHttpServletRequest()); }); assertEquals(ErrorCodes.NULL_PID, exception.getErrorCode()); // 假设CustomException有getErrorCode方法 }
(4)修正语法细节
- 原测试代码中
myModelClass.setPID(null)后缺少分号; - 异常断言建议直接判断错误码而非消息包含,避免因消息格式变更导致测试失败。
(5)可选:用MockMvc模拟HTTP请求
如果要更贴近真实的HTTP请求场景,可以用MockMvc模拟POST请求,验证Controller的响应:
@Test public void nullPidTestWithMockMvc() throws Exception { // 构造请求体(假设MyModelClass可以序列化为JSON) String requestBody = "{\"pid\": null}"; when(myservice.isNull(null)).thenReturn(true); mockMvc.perform(post("/sendNotificationToUsers") .contentType(MediaType.APPLICATION_JSON) .content(requestBody)) .andExpect(status().isBadRequest()) // 假设CustomException被全局异常处理器转为400状态码 .andExpect(jsonPath("$.errorCode").value(ErrorCodes.NULL_PID)); }
内容的提问来源于stack exchange,提问作者user22410466
相关产品推荐
相关产品推荐

