如何在 JUnit 测试中使用 Spring defaultValidator
Posted
技术标签:
【中文标题】如何在 JUnit 测试中使用 Spring defaultValidator【英文标题】:How to use Spring defaultValidator in JUnit tests 【发布时间】:2022-01-13 06:08:12 【问题描述】:我一直在我的测试类上使用@SpringJunitConfig
来减少@SpringBootTest
的上下文加载时间。这在我只使用自己的类时效果很好,因为我可以轻松指定要加载的包/类。
现在我正在尝试使用 Spring 的默认参数验证。基于其他 SO 答案,我创建并加载了 defaultValidator
bean。但是,当我的测试调用带有验证的方法并且测试失败时,不会触发 Spring 的默认验证。我知道被测类上的注释是正确的,因为当我切换到@SpringBootTest
时,测试通过了。
还有什么想法吗?
这是我最接近的一次,但 Spring 不会自动验证,除非我切换到 @SpringBootTest
,它会加载完整的上下文并且速度太慢。
测试类
@SpringJUnitConfig()
class UserServiceImplTest
@Configuration
@ComponentScan(basePackages = "com.user" ,
includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = UserMapper.class,
UserServiceImpl.class), useDefaultFilters = false)
static class ConfigMe
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder()
return new BCryptPasswordEncoder();
@Bean
public Validator defaultValidator()
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
return factory.getValidator();
@Autowired
private UserServiceImpl userService;
@Autowired
private UserMapper mapper;
@Autowired
@Qualifier("defaultValidator")
Validator validator;
@MockBean
private UserDao userDao;
// tests for UserServiceImpl that require valdiation of method arguments
// e.g. public UserDto findUser(@NotNull @Size(min = 30, max = 30) String userUnique)
@Test
void givenInvalidUnique_whenFind_thenConstraintException()
assertThrows(ConstraintViolationException.class, () ->
userService.findUser(null); // null
);
服务类
@Service
@Transactional
@Validated
public class UserServiceImpl implements UserService
@Override
@Transactional(readOnly = true)
public UserDto findUser(@NotNull @Size(min = 30, max = 30) String userUnique)
log.trace("findUser called with unique []", userUnique);
Optional<User> foundUser = userDao.findByUserUnique(userUnique);
if (foundUser.isEmpty())
throw new MyEntityNotFoundException(String.format("Could not find user with unique of [%s]", userUnique));
return mapper.UserEntityToDto(foundUser.get());
// other service methods
【问题讨论】:
@xerx593 是的。将服务类添加到问题中。 完全没有(预期的)异常?或错误的类型? (测试失败的确切原因是什么?) 【参考方案1】:defaultValidator
bean 由 spring-boot 自动配置内容定义,如果有任何带有 @EnableAutoConfiguration
注释的 @Configuration
bean 将启用。
但@EnableAutoConfiguration
默认情况下会考虑所有由 spring-boot 定义的自动配置内容(即那些在spring.factories
中定义的内容),这对于编写单元测试来说可能太多了。所以还有另一个注解叫做@ImportAutoConfiguration
,它可以只导入和应用一个指定的自动配置类。
由于 defaultValidator
bean 是在 ValidationAutoConfiguration
中定义的,这意味着您可以简单地通过以下方式导入它:
@SpringJUnitConfig
class UserServiceImplTest
@Configuration
@ComponentScan(basePackages = "com.user" , includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = UserMapper.class, UserServiceImpl.class), useDefaultFilters = false)
@ImportAutoConfiguration(ValidationAutoConfiguration.class)
static class ConfigMe
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder()
return new BCryptPasswordEncoder();
提示:要找出哪个自动配置类定义了defaultValidator
bean,您可以在application.properties
中启用调试模式:
debug=true
然后像往常一样启动spring-boot应用程序,它将打印出以下条件评估报告:
============================
CONDITIONS EVALUATION REPORT
============================
Positive matches:
-----------------
ValidationAutoConfiguration matched:
- @ConditionalOnClass found required class 'javax.validation.executable.ExecutableValidator' (OnClassCondition)
- @ConditionalOnResource found location classpath:META-INF/services/javax.validation.spi.ValidationProvider (OnResourceCondition)
ValidationAutoConfiguration#defaultValidator matched:
- @ConditionalOnMissingBean (types: javax.validation.Validator; SearchStrategy: all) did not find any beans (OnBeanCondition)
【讨论】:
出色的答案,尤其是提示,因为它可以帮助我更好地了解如何在未来解决类似的需求!以上是关于如何在 JUnit 测试中使用 Spring defaultValidator的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Mockito 和 JUnit 在 Spring Boot 中测试 POST 方法
如何在使用 @RunWith 和 @ContextConfiguration 注释的 jUnit 测试中访问 Spring 上下文?
如何在单个 JUnit 测试中运行两个 Spring Boot 微服务?
如何在 Spring Boot 和 JUnit 测试中定义 spring.config.location?