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

SpringBoot自定义约束校验器单元测试报“No target Validator set”错误

问题描述

我有一个SpringBoot应用,通过如下方式注入LocalValidatorFactoryBean:

private LocalValidatorFactoryBean validatorFactoryBean;

@Autowired
public void setValidatorFactoryBean(LocalValidatorFactoryBean validatorFactoryBean) {
    this.validatorFactoryBean = validatorFactoryBean;
}

我在Car类上定义了自定义校验器,并通过以下代码执行校验:

Set<ConstraintViolation<Car>> constraintViolations = validatorFactoryBean.validate(myCar);

上述代码在应用中运行正常,但在TestNG单元测试中执行validatorFactoryBean.validate(myCar)时,出现“No target Validator set”错误。

我在单元测试中通过如下方式设置validatorFactoryBean:

@InjectMocks
LocalValidatorFactoryBean validatorFactoryBean;

并通过调用setValidatorFactoryBean方法将其传入待测试类。调试发现,该validatorFactoryBean无法识别主代码中的所有ConstraintValidator实现。

我的汽车约束校验器实现如下:

public class CarConstraintImpl implements ConstraintValidator<CarConstraint, Request> {

    @Inject
    FuelDependency fuelDependency;

    public CarConstraintImpl() {
    }
    @Override
    public boolean isValid(Request req, ConstraintValidatorContext constraintContext) {
        try {
            fuelDependency.check(req);
        } catch (Exception e) {
            //some code
        }
        return true;
    }

}

请问如何让validatorFactoryBean识别所有ConstraintValidator实现?

解决方案

问题核心是@InjectMocks直接实例化的LocalValidatorFactoryBean没有经过Spring初始化,既无法扫描注册自定义ConstraintValidator,也没有创建内部的Validator实例,才会触发“No target Validator set”错误。以下是几种可行的解决方式:

1. 借助Spring Test上下文初始化校验器

在TestNG测试类上添加Spring相关注解,让Spring容器负责初始化LocalValidatorFactoryBean,它会自动扫描并注册所有自定义校验器,同时处理依赖注入:

@SpringBootTest
public class YourTestClass {

    @Autowired
    private LocalValidatorFactoryBean validatorFactoryBean;

    @Autowired
    private YourServiceClass yourService; // 待测试类

    @Test
    public void testValidation() {
        Car myCar = new Car();
        Set<ConstraintViolation<Car>> violations = validatorFactoryBean.validate(myCar);
        // 编写断言或其他测试逻辑
    }
}

这种方式会启动完整的Spring上下文,适合集成测试,能保证校验器及其依赖(如FuelDependency)都被正确初始化。

2. 手动初始化LocalValidatorFactoryBean

如果想避免启动完整Spring上下文,可手动配置并初始化LocalValidatorFactoryBean,指定扫描包并处理依赖注入:

public class YourTestClass {

    private LocalValidatorFactoryBean validatorFactoryBean;
    private YourServiceClass yourService;

    @BeforeMethod
    public void setUp() {
        validatorFactoryBean = new LocalValidatorFactoryBean();
        
        // 创建Spring Bean工厂,用于注入校验器中的依赖
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        // 模拟FuelDependency实例(或根据需要注入真实实例)
        FuelDependency mockFuelDependency = Mockito.mock(FuelDependency.class);
        beanFactory.registerSingleton("fuelDependency", mockFuelDependency);
        validatorFactoryBean.setBeanFactory(beanFactory);

        // 指定自定义校验器所在的包路径,让校验器工厂扫描注册
        validatorFactoryBean.setPackagesToScan("com.yourpackage.constraints");
        validatorFactoryBean.setValidationMessageSource(new ResourceBundleMessageSource());

        // 执行初始化,触发校验器扫描和内部Validator创建
        validatorFactoryBean.afterPropertiesSet();

        // 将初始化好的校验器注入待测试类
        yourService = new YourServiceClass();
        yourService.setValidatorFactoryBean(validatorFactoryBean);
    }

    @Test
    public void testValidation() {
        Car myCar = new Car();
        Set<ConstraintViolation<Car>> violations = validatorFactoryBean.validate(myCar);
        // 编写测试逻辑
    }
}

这种方式适合单元测试,通过手动配置减少上下文启动开销,同时保证校验器正常工作。

3. Spring Test环境下用@MockBean替代@InjectMocks

如果已经在使用Spring Test但不想启动完整@SpringBootTest,可以用@MockBean模拟依赖,同时让Spring管理LocalValidatorFactoryBean:

@ContextConfiguration(classes = {YourValidationConfig.class})
public class YourTestClass extends AbstractTestNGSpringContextTests {

    @Autowired
    private LocalValidatorFactoryBean validatorFactoryBean;

    @MockBean
    private FuelDependency fuelDependency;

    @Autowired
    private YourServiceClass yourService;

    @Test
    public void testValidation() {
        // 编写测试逻辑
    }
}

配套的配置类YourValidationConfig用于注册相关Bean:

@Configuration
public class YourValidationConfig {
    @Bean
    public LocalValidatorFactoryBean validatorFactoryBean() {
        LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
        bean.setPackagesToScan("com.yourpackage.constraints");
        return bean;
    }

    @Bean
    public YourServiceClass yourServiceClass() {
        return new YourServiceClass();
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 19:54:58