ConstraintValidators, созданные пользовательским ConstraintValidatorFactory, не привязаны к ValidatorContext - PullRequest
0 голосов
/ 13 октября 2019

Я работаю над тестами JUnit для валидаторов ограничений с зависимостями. Я создал пользовательский ConstraintValidatorFactory, который имеет доступ к макетам Mockito, и в основном все работает.

Чтобы уменьшить накладные расходы на инициализацию, я хотел, чтобы ValidatorFactory статически инициализировался только один раз в пользовательском правиле JUnit и для каждогопри выполнении теста будет использоваться новый ValidatorContext.

К сожалению, валидатор ограничения для конкретной «точки валидации» запрашивается только один раз из фабрики валидатора ограничения, независимо от используемого контекста валидатора (см. пример кода ниже).

Я бы ожидал, что при использовании контекста с пользовательской фабрикой валидаторов ограничений все валидаторы ограничений всегда запрашиваются из этой фабрики и не разделяются во всех контекстах. Я протестировал двух провайдеров проверки бинов, и оба они ведут себя одинаково, поэтому, вероятно, он работает как задумано. Но тогда каков типичный вариант использования фабрики валидаторов пользовательских ограничений внутри контекста?

public class ValidatorContextTest {

    @Rule
    public final MockitoRule mockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);

    @Mock
    private ConstraintValidatorFactory constraintValidatorFactory;

    @Test
    public void test() {
        final ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();

        when(constraintValidatorFactory.getInstance(TestBeanAnnotationValidator.class))
                .thenReturn(new TestBeanAnnotationValidator());

        for (int i = 0; i < 2; i++) {
            final Validator validator = validatorFactory
                    .usingContext()
                    // assumption: constraint validators instantiated by this factory are "bound" to this very context
                    .constraintValidatorFactory(constraintValidatorFactory)
                    .getValidator();
            validator.validate(new TestBean());
        }

        // fails with "Wanted 2 times, but was 1 time"
        verify(constraintValidatorFactory, times(2)).getInstance(TestBeanAnnotationValidator.class);
    }

    @TestBeanAnnotation
    private static class TestBean {
        // no extras
    }

    @Constraint(validatedBy = {TestBeanAnnotationValidator.class})
    @Documented
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface TestBeanAnnotation {

        String message() default "Test message";

        Class<?>[] groups() default {};

        Class<? extends Payload>[] payload() default {};

    }

    public static class TestBeanAnnotationValidator implements ConstraintValidator<TestBeanAnnotation, TestBean> {

        // fields, constructor etc.

        public void initialize(TestBeanAnnotation testBeanAnnotation) {
            // NOP
        }

        public boolean isValid(TestBean testBean, ConstraintValidatorContext constraintValidatorContext) {
            return false;
        }

    }

}

...