当前位置: 首页 > 知识库问答 >
问题:

如何测试在java中实现ConstraintValidator的验证器?

吉毅
2023-03-14

我有一个“AllowedValuesValidator.java”类:

public class AllowedValuesValidator implements ConstraintValidator<AllowedValues, String> {

    String[] values;
    String defaultValue;

    @Override
    public void initialize(AllowedValues constraintAnnotation) {
        values = constraintAnnotation.allowedValues();
        defaultValue = constraintAnnotation.defaultValue();
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (!StringUtils.isEmpty(defaultValue) && StringUtils.isEmpty(value)) {
            value = defaultValue;
        }

        if (!StringUtils.isEmpty(value) && !Arrays.asList(values).contains(value)) {
            return false;
        }
        return true;
    }
}

以及相应的接口类:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = AllowedValuesValidator.class)
public @interface AllowedValues {

    String message();

    String fieldName();

    int fieldNumber();

    String[] allowedValues() default {"Y", "N"};

    String defaultValue() default "";
}

我希望能够编写一个单元测试类来测试验证器中的直接逻辑。但我在谷歌上搜索的大多数地方似乎都给出了测试类的例子,我们基本上测试了给定模型类的所有验证器,例如:

    @BeforeClass
    public static void setup() {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        validator = factory.getValidator();
    }

    @Test
    public void testEmailExistsIncorrect() {

        Set<constraintviolation<usercredentialsdto>> violations = validator
                .validate(credentials, UserCredentialsDto.class);
        Assert.assertEquals(1, violations.size());
    }

我不想构建模拟模型来测试所有验证器。有没有一种方法可以创建一个单独的测试类,只在一个验证器中直接测试逻辑,而不使用任何其他模型类等?

共有3个答案

翟青青
2023-03-14

注释:

@Documented
@Constraint(validatedBy = NoWhitespacesValidator.class)
@Target({ FIELD })
@Retention(RUNTIME)
public @interface NoWhitespaces {
    String message() default "Not valid";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

验证器:

public class NoWhitespacesValidator implements ConstraintValidator<NoWhitespaces, String> {
    @Override public boolean isValid(String value, ConstraintValidatorContext context) {
        return !value.contains(" ");
    }
}

测试案例:

class NoWhitespacesTest {

    private NoWhitespacesValidator validator = new NoWhitespacesValidator();

    @Nested
    class NoWhitespaceValidFlow {
        @Test
        void isValid_shouldReturnTrue_whenNoWhitespaces() {
            assertTrue(isValid(""));
            assertTrue(isValid("foo.bar"));
        }
    }

    @Nested
    class NoWhitespacesInvalidFlow {
        @Test
        void isValid_shouldReturnFalse_whenAtLeastOneWhitespace() {
            assertFalse(isValid(" "));
            assertFalse(isValid("foo bar"));
            assertFalse(isValid("  foo"));
            assertFalse(isValid("foo  "));
        }
    }

    private boolean isValid(String value) {
        return validator.isValid(value, null);
    }
}
高森
2023-03-14

我使用了以下模式:

@RunWith(MockitoJUnitRunner.class)
public class AllowedValuesValidatorTest {

    @Mock
    AllowedValuesValidator allowedValuesValidator;

    @Mock
    ConstraintValidatorContext constraintValidatorContext;

    @Before
    public void setUp() {

        doCallRealMethod().when(allowedValuesValidator).initialize(any());
        when(allowedValuesValidator.isValid(any(), any())).thenCallRealMethod();

        AllowedValuesValidatorTestClass testClass = new AllowedValuesValidatorTestClass();

        allowedValuesValidator.initialize(testClass);

    }

    @Test
    public void testIsValidWithValidValues() {
        assertTrue(allowedValuesValidator.isValid("Value", constraintValidatorContext));
    }

    private class AllowedValuesValidatorTestClass implements AllowedValues {

        @Override
        public String message() {
            return "Test Message";
        }

        @Override
        public Class<?>[] groups() {
            return new Class[]{};
        }

        @Override
        public Class<? extends Payload>[] payload() {
            return new Class[]{};
        }

        @Override
        public Class<? extends Annotation> annotationType() {
            return AllowedValues.class;
        }

    }

}

我们可以模仿我们正在测试的课程。由于注释只是一个接口,我们可以在具体的实现中作为参数进行初始化(为了正确初始化测试,您可以使其以任何方式运行)。然后,可以将模拟的ConstraintValidatorContext传递给isValid方法。然而,根据该方法的功能,您可能需要做一些额外的工作,如果它与上下文交互,您可能需要做一些进一步的模拟。

琴俊人
2023-03-14

您可以单独测试验证器。rub当然是initialize方法,因为它需要注释的实例。你基本上有三个选择:

  1. 添加第二个initialize方法,该方法直接获取所需的参数。然后可以使用此方法初始化验证器。如果您的测试驻留在同一个包中,您还可以使此方法只显示包

--

private AllowedValues createAnnotation(String[]values, String defaultValue) {
  AnnotationDescriptor<AllowedValues> descriptor = new AnnotationDescriptor<AllowedValues>( AllowedValues.class );
  descriptor.setValue( "values", values );
  descriptor.setValue( "defaultValue", defaultValue );

  return AnnotationFactory.create( descriptor );
}

您需要依赖于Hibernate验证器内部类,但出于测试目的,这应该可以。当然,您也可以创建自己的代理框架。

 类似资料:
  • 本文向大家介绍Java如何实现验证码验证功能,包括了Java如何实现验证码验证功能的使用技巧和注意事项,需要的朋友参考一下 Java如何实现验证码验证功能呢?日常生活中,验证码随处可见,他可以在一定程度上保护账号安全,那么他是怎么实现的呢? Java实现验证码验证功能其实非常简单:用到了一个Graphics类在画板上绘制字母,随机选取一定数量的字母随机生成,然后在画板上随机生成几条干扰线。 首先,

  • 任何人都曾经使用过Spring启动并遇到这个错误。 我知道这与此有关: 任何依赖于特定于实现的ConstraintValidatorFactory行为(依赖项注入、无参数构造函数等)的约束实现都不被认为是可移植的。 但我的验证器不能是可移植的,因为它需要回购协议才能工作,所以这不是一个选项。 我尝试添加一个no-args构造函数到我的验证器,但然后我得到这个: 我还试图重写LocalValidat

  • 我有一个这样的处理程序和一个自定义注释@validrequest: 注释本身看起来是这样的: 而验证器是这样的: 问题是验证被完全忽略了。我可以发送任何事件有或没有身体和一切工作无一例外。我做的一切都是根据Micronout文档,会有什么问题吗? https://docs.micronaut.io/latest/guide/index.html#BeanValidation

  • 斯波克规格 如何测试从“Specification下的方法(teamservices.deleteteam())”调用的“Specification下的类”teamservices.moveAssets())方法? https://github.com/spockframework/spock/discussions/1346

  • 问题内容: 所以,我有自定义的验证,当我设定return值,false那么它的工作原理- 但是,当我尝试在该部分中引发异常时,出现错误,该问题是由我的自定义异常引起的: 放置了例外 @Controller ExceptionResolover 编辑:抛出InvalidPayloadException异常UserNameUniqueValidator返回自定义消息,所以我避免BindingResul

  • 我有一门课: 如何测试它?我试过这样做:如何使用JUnit测试类的验证注释?但这不起作用,因为我的验证器中的validate方法需要传递给它的方法签名的类。 我不知道是否可以将此错误传递给验证器。还有别的办法吗?