如何测试在java中实现 ConstraintValidator 的 Validator?

我有一个“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());
    }

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


答案 1

您可以单独测试验证程序。rub 当然是初始化方法,因为它需要一个注释的实例。您基本上有三种选择:

  1. 添加第二个初始化方法,该方法直接采用所需的参数。然后,可以使用此方法初始化验证程序。您还可以使此方法仅包可见,前提是您的测试位于同一包中
  2. 将测试批注放在测试类中的某个位置,并通过反射检索它,以便将其传递给 initialize 方法。
  3. 使用注释代理。这也是Hibernate Validator本身在内部使用的内容,以防约束是通过XML配置的或测试所必需的。休眠验证器中有两个类可以使用 和 。代码有点像这样:AnnotationDescriptorAnnotationFactory

--

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 Validator 内部类,但出于测试目的,这应该没问题。当然,您也可以创建自己的代理框架。


答案 2

我使用了以下模式:

@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;
        }

    }

}

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


推荐