[英]hibernate validator throws exception ValidationException: HV000028 for @Past annotation
[英]javax.validation.ValidationException: HV000028: Unexpected exception during isValid in Test
我不知道如何为自定义约束验证器编写单元测试。 我有以下验证器类:
@Slf4j
@AllArgsConstructor
@NoArgsConstructor
public class SchoolIdValidator implements ConstraintValidator<ValidSchoolId, String> {
private SchoolService schoolService;
@Override
public void initialize(ValidSchoolId constraintAnnotation) {}
@Override
public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
return schoolService.isValidSchoolId(s);
}
}
验证器由以下注释使用:
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = SchoolIdValidator.class)
public @interface ValidSchoolId {
String message() default "Must be a valid school. Found: ${validatedValue}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
SchoolService
是一个类,它通过使用 ApiClient 调用 School Api,ApiClient 是一个具有通用 restTemplate 请求的通用类:
@Service
@AllArgsConstructor
public class SchoolService {
private ApiClient apiSchoolClient;
public Boolean isValidSchoolId(String schoolId){
try {
ResponseEntity res = apiSchoolClient.get(
String.format("/stores/%s", schoolId), Object.class, null);
return res.getStatusCode().is2xxSuccessful();
} catch (HttpClientErrorException e) {
if(e.getStatusCode().value() == 404)
return false;
else
throw new TechnicalException("Can't get response from school Api");
} catch(RestClientException e) {
throw new TechnicalException("Can't get response from School Api");
}
}
}
最后是学生类:
@Data
public class Student {
private String id;
private String firstName;
private String lastName;
@ValidSchoolId
private String schoolId;
}
当我运行该应用程序时,它运行良好。 但是,它根本不适用于以下 Test 类:
@RunWith(MockitoJUnitRunner.class)
@ExtendWith(SpringExtension.class)
public class SchoolIdValidatorTest {
Validator validator;
@InjectMocks
private SchoolService schoolService;
@Mock
private ApiClient apiSchoolClient;
@Before
public void setUp() throws Exception {
validator = Validation.buildDefaultValidatorFactory().getValidator();
MockitoAnnotations.initMocks(this);
}
@Test
public void isValid_SchoolIdExists_ShouldValidate() {
Mockito.when(this.apiSchoolClient.get(Mockito.eq("/schools/12"), Mockito.any(), Mockito.any()))
.thenReturn(new ResponseEntity<>(HttpStatus.OK));
//given
Student student = new Student();
simulation.setSchoolId("12");
//when
Set<ConstraintViolation<Student>> violations = validator.validate(student);
//then
assertEquals(0, violations.size());
}
当它出现时SchoolIdValidator
schoolService
总是null
。 所以,它总是在 SchoolIdValidator.isValid 上抛出一个 NPE。 如果有人有解决方案,那将非常有帮助。
感谢阅读和帮助。
这里的@InjectMocks
可能是问题所在。
@RunWith(MockitoJUnitRunner.class)
@ExtendWith(SpringExtension.class)
public class SchoolIdValidatorTest {
Validator validator;
@InjectMocks
private SchoolService schoolService;
随着
Validation.buildDefaultValidatorFactory().getValidator()
我的假设下SchoolService
通常是一个Spring管理的bean,并SchoolIdValidator
会有它注入。 通过使用@InjectMocks
您是在说这不是 Spring 托管的 bean。 这个类是由 Mockito 实例化的,所以它永远不会被注入到你的验证器中。
我不确定这里的正确解决方案是什么,因为您没有发布任何配置类。 最有可能的,你需要的是你的实例验证,额外的测试配置类ApiClient
并注入您的SchoolService
。 您也可以使用@MockBean
模拟ApiClient
,这将使其成为 Spring 管理的 bean,但也允许模拟。
有点相关,你在这里确实有构造函数。 没有理由使用@InjectMocks
。 只需使用new SchoolService(apiSchoolClient)
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.