В Spring Roo в действии, глава 3, я обсуждаю, как Roo автоматически запускает Bean Validators при сохранении живой сущности. Однако при запуске модульных тестов у нас вообще нет живой сущности и контейнера Spring. Так как же мы можем выполнить проверку, не затрагивая приложение Roo и базу данных?
Следующий пост — вспомогательный материал из будущей книги Кена Римпла и Срини Пенчикала «Весна в действии» с Гордоном Диккенсом. Вы можете приобрести издание книги MEAP и принять участие в форуме авторов по адресу www.manning.com/rimple .
Ответ заключается в том, что мы должны сами запустить систему проверки в рамках теста. Мы можем использовать метод getNewTransientEntityName класса CourseDataOnDemand, чтобы сгенерировать допустимую временную сущность JPA. Тогда мы можем:
- Имитация статических методов сущностей, таких как findById, чтобы вернуть предварительно изготовленные экземпляры классов вашей сущности
- Инициализируйте механизм проверки, загрузите механизм механизма проверки bean-компонента JSR-303 и выполните проверку своей сущности.
- Установите любые подходящие свойства для применения к определенному условию теста
- Инициализируйте тестовый экземпляр средства проверки сущности и подтвердите, что возвращаются соответствующие результаты проверки
Концепция в действии …
Дана Студенческая сущность со следующим определением:
@RooEntity @RooJavaBean @RooToString public class Student { @NotNull private String emergencyContactInfo; ... }
В приведенном ниже листинге показан метод модульного тестирования, который гарантирует, что проверка NotNull сработает против пропущенной экстренной контактной информации на объекте Student:
@Test public void testStudentMissingEmergencyContactValidation() { // setup our test data StudentDataOnDemand dod = new StudentDataOnDemand(); // tell the mock to expect this call Student.findStudent(1L); // tell the mocking API to expect a return from the prior call in the form of // a new student from the test data generator, dod AnnotationDrivenStaticEntityMockingControl.expectReturn( dod.getNewTransientStudent(0)); // put our mock in playback mode AnnotationDrivenStaticEntityMockingControl.playback(); // Setup the validator API in our unit test LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); validator.afterPropertiesSet(); // execute the call from the mock, set the emergency contact field // to an invalid value Student student = Student.findStudent(1L); student.setEmergencyContactInfo(null); // execute validation, check for violations Set<ConstraintViolation<Student>> violations = validator.validate(student, Default.class); // do we have one? Assert.assertEquals(1, violations.size()); // now, check the constraint violations to check for our specific error ConstraintViolation<Student> violation = violations.iterator().next(); // contains the right message? Assert.assertEquals("{javax.validation.constraints.NotNull.message}", violation.getMessageTemplate()); // from the right field? Assert.assertEquals("emergencyContactInfo", violation.getPropertyPath().toString()); }
Анализ
Тест начинается с объявления объекта StudentOnDemand, который мы будем использовать для генерации наших тестовых данных. Мы познакомимся с более сложным использованием DataOnDemand Framework позже в этой главе. Пока помните, что мы можем использовать этот класс для создания экземпляра сущности со случайно назначенными действительными данными. Затем мы требуем, чтобы тест вызывал метод Student.findStudent, передавая ему ключ 1L. Далее мы сообщим платформе имитации сущностей, что вызов должен вернуть новый временный экземпляр Student. На данный момент, мы определили наше поведение статического насмешки, поэтому мы переведем среду насмешки в режим воспроизведения.
Затем мы выполняем фактический вызов Student.findById (1L), на этот раз сохраняя результат как переменную-член student. Этот вызов отключит макет, который вернет новый временный экземпляр. Затем мы устанавливаем поле emergencyContactInfo значение null, чтобы оно стало недействительным, так как оно аннотировано аннотацией @NotNull. Теперь мы готовы установить нашу структуру проверки bean-компонентов.
Мы создаем экземпляр LocalValidatorFactoryBean, который будет загружать платформу проверки Bean в методе afterPropertiesSet (), который определен для любого Spring Bean, реализующего InitializingBean. Мы должны вызвать этот метод сами, потому что Spring не участвует в нашем модульном тесте. Теперь мы готовы запустить нашу проверку и подтвердить правильность поведения.
Мы вызываем метод validate нашего валидатора, передавая ему экземпляр студента и стандартную группу валидации по умолчанию, которая запускает валидацию. Затем мы проверим, что у нас только один сбой проверки и что шаблон сообщения об ошибке совпадает с шаблоном проверки @NotNull. Мы также проверяем, чтобы поле, которое вызвало проверку, было нашим полем emergencyContactInfo.
В нашем ответном обратном вызове мы можем запустить Bean Validation Framework и выполнить метод validate для нашей сущности. Таким образом, мы можем использовать наш экземпляр компонента любым способом, каким захотим, и вместо того, чтобы сохранять сущность, можем выполнить этап проверки и корректно завершить работу.
Предостережения …
Здесь есть несколько неправильных вещей. Прежде всего, классы Data on Demand на самом деле используют Spring для внедрения отношений друг с другом, в которых я зарегистрировал ошибку как ROO-2497 . Вы можете переопределить настройку класса данных по требованию и вручную создать DoD для ссылающегося класса, что нормально. Они планируют поработать над этой ошибкой для Roo 1.2, поэтому она должна быть исправлена где-то в ближайшие несколько месяцев.
Кроме того, осознайте, что это НЕ легко сделать по сравнению с написанием интеграционного теста. Однако этот тест выполняется заметно быстрее. Если у вас есть какая-то сложная логика, которую вы прикрепили к
@AssertTrue
аннотация, это способ проверить это изолированно.
С http://www.rimple.com/tech/2011/7/17/testing-entity-validations-with-a-mock-entity-roo-in-action.html