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

使用MockMvc测试依赖Spring Validator的SpringBoot控制器遇注入异常

解决Spring Boot RestController自定义Validator单元测试找不到的问题

这个问题我之前帮同事排查过,本质就是测试上下文里没正确加载你的自定义JobValidator,或者构造控制器实例时没给全依赖。毕竟你用的是构造注入,控制器的所有构造参数都得有合法的实例才能初始化成功。下面给你两种靠谱的解决方案,都是用MockMvc来完成测试的:

方案一:用@WebMvcTest结合@MockBean(官方推荐的Web层测试方式)

这种方式会加载最小化的Web测试上下文,既能利用Spring的自动配置,又能Mock掉不需要的业务依赖,同时把自定义Validator纳入上下文:

  1. 测试类的核心配置:

    • 用@WebMvcTest(JobController.class)指定要测试的控制器,Spring会自动加载Web层相关的Bean
    • 用@Import(JobValidator.class)把你的自定义Validator导入测试上下文,这样Spring就能找到它并注入到控制器里
    • 用@MockBean来MockJobService,避免测试时依赖真实的业务逻辑实现
  2. 完整示例代码:

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@WebMvcTest(JobController.class)
@Import(JobValidator.class) // 关键:把自定义Validator加入测试上下文
public class JobControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean // Mock业务层服务,隔离真实逻辑
    private JobService jobService;

    @Test
    void testInvalidJobRequest() throws Exception {
        // 构造不符合校验规则的JSON请求
        String invalidJobJson = "{\"title\":\"\",\"salary\":-100}";

        mockMvc.perform(post("/jobs")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(invalidJobJson))
                .andExpect(status().isBadRequest()); // 校验失败,预期返回400
    }

    @Test
    void testValidJobRequest() throws Exception {
        String validJobJson = "{\"title\":\"Senior Java Developer\",\"salary\":18000}";

        mockMvc.perform(post("/jobs")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(validJobJson))
                .andExpect(status().isOk()); // 校验通过,预期返回200
    }
}

这里要注意:如果你的JobValidator本身是用@Component标记的Spring Bean,那其实不用@Import也能被上下文加载,但如果它只是普通类(没加Spring注解),@Import就必须加,不然Spring找不到这个类的实例。

方案二:手动构造控制器实例(灵活度更高的测试方式)

如果你不想依赖Spring的测试上下文,想完全手动控制所有依赖的实例化,那可以用这种方式:

  1. 核心步骤:

    • 用Mockito来MockJobService
    • 手动创建JobValidator的实例(或者也可以Mock它,如果你不想测试校验逻辑,只测控制器的其他逻辑)
    • 手动构造JobController实例,把Validator和Mock的Service都传进去
    • 用MockMvcBuilders.standaloneSetup构建MockMvc,并显式设置Validator
  2. 完整示例代码:

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.http.MediaType;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

public class JobControllerManualTest {

    private MockMvc mockMvc;

    @Mock
    private JobService jobService; // Mock业务层依赖

    private JobValidator jobValidator;
    private JobController jobController;

    @BeforeEach
    void setUp() {
        MockitoAnnotations.openMocks(this); // 初始化Mockito的Mock实例
        jobValidator = new JobValidator(); // 创建真实的Validator实例
        jobController = new JobController(jobValidator, jobService); // 手动构造控制器

        // 构建MockMvc并绑定控制器,显式设置Validator确保校验生效
        mockMvc = MockMvcBuilders.standaloneSetup(jobController)
                .setValidator(jobValidator)
                .build();
    }

    @Test
    void testInvalidJobRequest() throws Exception {
        String invalidJobJson = "{\"title\":\"\",\"salary\":-5000}";

        mockMvc.perform(post("/jobs")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(invalidJobJson))
                .andExpect(status().isBadRequest());
    }
}

这种方式完全脱离Spring上下文,适合需要高度自定义依赖的测试场景,比如你想给Validator传一些特殊的配置参数时,手动实例化会更方便。

额外排查要点

如果还是遇到Validator找不到的错误,可以检查这几点:

  • 确认JobValidator的类名、构造方法有没有拼写错误,和控制器构造注入的参数类型是否完全匹配
  • 如果Validator依赖其他Spring Bean,那在方案一中需要把这些依赖也加入测试上下文(用@MockBean或者@Import),方案二中要手动注入这些依赖
  • 如果你用的是Spring Boot 2.x以上版本,确保spring-boot-starter-test依赖已经正确引入,里面包含了MockMvc和Mockito的相关包

内容的提问来源于stack exchange,提问作者Felix

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 07:53:08