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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 04:27:03