Модульное тестирование валидаторов Hibernate

Я читал Hibernate документы о проверочных тестах класса, и я не нашел никакого решения своей «проблемы». Я хочу протестировать свои собственные валидаторы. Например, допустим, у меня есть следующий класс:

public class User {

    @NotEmpty(message = "{username.notSpecified}")
    private String username;

    @NotEmpty
    @Size(min = 6, message = "{password.tooShort")
    private String password;

    @NotEmpty(message = "{city.notSpecified}")
    private String city;

    /* getters & setters omitted */
}

И я хочу проверить, что каждый пользователь находится в городе Барселона. Для этого у меня была бы реализация пользовательского валидатора пользователя следующим образом:

public class UserValidator implements Validator {

    @Autowired 
    private Validator validator;

    @Override
    public boolean supports(Class<?> clazz) {
        return User.class.equals(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {
         validator.validate(target,errors);
         User user = (User) target;
         if(!(user.getCity().equals("Barcelona"))){
              errors.rejectValue("city", "city.notValid", "Invalid city"); 
         }
    }

}

Я понятия не имею, как использовать этот настраиваемый валидатор вместо валидатора по умолчанию, представленного в примере, и который проверяет только ограничения аннотированных полей, а не более «бизнес-логику». Какие-нибудь примеры или подсказки по этому поводу?

Спасибо!


person jarandaf    schedule 11.07.2013    source источник
comment
Какая весенняя версия?   -  person Yugang Zhou    schedule 11.07.2013
comment
Привет @Hippoom, я использую Spring 3.2.3.RELEASE. Я нашел этот пример (stackoverflow. com / questions / 9744988 /), но я думаю, что это не поддерживает группы проверки, которых нет в моем примере, но в какой-то момент все равно потребуется   -  person jarandaf    schedule 11.07.2013


Ответы (3)


Вам не нужно реализовывать Spring Validator для модульного тестирования, просто создайте для него экземпляр javax.validation.Validator.

import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;

import java.util.*;

import javax.validation.*;

import org.junit.*;

public class ApplierDtoUnitTests {

    private Validator validator = Validation.buildValidatorFactory().getValidator();
    private ApplierDto target = new ApplierDto();


    @Test
    public void brokenIfNullNameGiven() throws Exception {

        target.setName(null);

        Set<ConstraintViolation<ApplierDto>> constraintViolations = validator
            .validate(target);
        assertThat("unexpected size of constraint violations",
            constraintViolations.size(), equalTo(1));
    }
}

И я хотел бы использовать валидаторы для проверки формы или запроса RPC, а не какую-то «бизнес-логику» в моем опыте. С моей точки зрения, их непросто использовать на уровне домена.

person Yugang Zhou    schedule 11.07.2013
comment
Вам также необходимо ввести этот валидатор на свой контроллер, если вы тестируете некоторую проверку на контроллерах ... - person renanleandrof; 11.07.2013
comment
Вы можете использовать @Valid в ModelAttribute при использовании Spring 3.2.0 и выше, поэтому вам не нужно реализовывать пользовательский Spring Validator. - person Yugang Zhou; 11.07.2013
comment
Я не уверен, что правильно понял ваш ответ, но я бы сказал, что это проверяет только аннотации javax.validation, а не пользовательские Spring-валидаторы, что является моим случаем (см. static.springsource.org/spring/docs/3.2.x/). Я имею в виду, что в приведенном выше примере он будет проверять только ограничения пустого / размера, но не то, что единственное значение, принимаемое в поле city, - это Барселона. - person jarandaf; 11.07.2013

Поскольку я хочу написать модульный тест вместо интеграции Spring, я закончил следующее (даже работая в контексте Spring):

public class MyValidatorTest {

  private Validator validator;

  @Test
  public void check() {
    TestBean bean = new TestBean();
    bean.setMember(...);

    Errors actual = invokeValidator(bean);

    assertThat(actual.hasErrors(), is(true));
    // more assertions here
  }

  @Before
  public void createValidator() {
    // the validator to test is found be the @Constraint(validatedBy=...) in @MyValidation
    validator = new SpringValidatorAdapter(Validation.buildDefaultValidatorFactory().getValidator());
  }

  private Errors invokeValidator(Object bean) {
    BeanPropertyBindingResult errors = new BeanPropertyBindingResult(bean, "bean");
    ValidationUtils.invokeValidator(validator, bean, errors);
    return errors;
  }

  private static class TestBean {
    @MyValidation
    private AnyType member;
  }
}
person Arne Burmeister    schedule 01.07.2016

Наконец-то я нашел решение:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"/test-applicationContext.xml"})
public class UserValidatorTest {

    private static Logger logger = Logger.getLogger(UserValidatorTest.class);

    @Autowired
    private UserValidator validator;  //my custom validator, bean defined in the app context

    @Test
    public void testUserValidator(){
        User user = new User("name", "1234567", "Barcelona");
        BindException errors = new BindException(user, "user");
        ValidationUtils.invokeValidator(validator, user, errors);
        Assert.assertFalse(errors.hasErrors());
    }

}

Я проверил группы проверки (любые аннотации с указанными «группами»), и они также работают со статическим методом invokeValidator (просто добавляя их после параметра ошибок).

person jarandaf    schedule 11.07.2013