Как вызвать ConstraintValidationException в тестовом примере для свойств bean-компонента с аннотациями проверки?

Я пытаюсь проверить, что мои bean-компоненты имеют правильные аннотации проверки. Я использую весеннюю загрузку. Вот пример тестового случая:

package com.example.sandbox;

import static org.assertj.core.api.Assertions.assertThatThrownBy;

import javax.validation.ConstraintViolationException;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.validation.annotation.Validated;

@SpringBootTest
class ValidationTest {

    @Test
    void testConstructor() {
        TestedBean bean = new TestedBean(null);

        assertThatThrownBy(() -> checkIfValidated(bean)).isInstanceOf(ConstraintViolationException.class);
    }

    @Test
    void testSetter() {
        TestedBean bean = new TestedBean(null);

        assertThatThrownBy(() -> bean.setSomeProperty(null)).isInstanceOf(ConstraintViolationException.class);
    }

    private void checkIfValidated(@Valid TestedBean bean) {

    }

    @Validated
    class TestedBean {
        @NotNull
        private String someProperty;

        public TestedBean(String someProperty) {
            super();
            this.someProperty = someProperty;
        }

        public String getSomeProperty() {
            return someProperty;
        }

        public void setSomeProperty(@NotNull String someProperty) {
            this.someProperty = someProperty;
        }
    }
}

Я ожидаю, что вызов checkIfvalidated() и setSomeProperty(null) поднимет ConstraintViolationException, и тесты пройдут, но они оба терпят неудачу с:

java.lang.AssertionError: 
Expecting code to raise a throwable.
    at com.example.sandbox.ValidationTest.test(ValidationTest.java:20)
    ...

Мой пом.xml:

<?xml version = "1.0" encoding = "UTF-8"?>
<project xmlns = "http://maven.apache.org/POM/4.0.0"
    xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.0</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>com.example.springbootsandbox</artifactId>
    <version>0.0</version>
    <name>SpringBootSandbox</name>
    <description>Sandbox for Spring Boot</description>

    <properties>
        <java.version>11</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>6.1.5.Final</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

Почему здесь не поднят ConstraintViolationException? Свойство bean-компонента имеет аннотацию @NotNull, сам bean-компонент является @Validated, а сигнатура метода требует bean-компонента @Valid.

Есть ли простой способ вызвать это исключение в контексте моего тестового класса?

Когда я использую аннотации проверки сигнатур методов для интерфейса службы, все работает так, как ожидалось. Я не понимаю, где разница.

Интерфейс сервиса:

package com.example.sandbox;

import javax.validation.constraints.NotNull;

import org.springframework.validation.annotation.Validated;

@Validated
public interface IService {
    public void setValue(@NotNull String value);
}

Реализация услуги:

package com.example.sandbox;

import org.springframework.stereotype.Service;

@Service
public class SomeService implements IService {
    @Override
    public void setValue(String value) {
        // Do nothing
    }
}

Прецедент:

package com.example.sandbox;

import static org.assertj.core.api.Assertions.assertThatThrownBy;

import javax.validation.ConstraintViolationException;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class SomeServiceTests {
    @Autowired
    IService service;

    @Test
    void testSetValue() {
        assertThatThrownBy(() -> service.setValue(null)).isInstanceOf(ConstraintViolationException.class);
    }
}

==> Тест пройден.


Рабочий код в соответствии с данным ответом:

Тестовый класс:

@SpringBootTest
class ValidationTest {
    @Autowired
    private Validator validator; // Using the default validator to test property annotations

    @Autowired
    private TestedBeanService service; // Using a service to test method annotations

    @Test
    void testPropertyAnnotations() {
        TestedBean bean = new TestedBean(null);
        Set<ConstraintViolation<TestedBean>> violations = validator.validate(bean);
        assertThat(violations).isNotEmpty();
    }

    @Test
    void testMethodAnnotations() {
        TestedBean bean = new TestedBean(null);
        assertThatThrownBy(() -> service.setBeanProperty(bean, null)).isInstanceOf(ConstraintViolationException.class);
    }
}

Тестируемый боб:

@Validated
class TestedBean {
    @NotNull
    private String someProperty;

    public TestedBean(String someProperty) {
        super();
        this.someProperty = someProperty;
    }

    public String getSomeProperty() {
        return someProperty;
    }

    public void setSomeProperty(String someProperty) { // No more annotation on setter
        this.someProperty = someProperty;
    }
}

Интерфейс сервиса:

@Validated
public interface TestedBeanService {
    // method annotation on the interface method
    void setBeanProperty(TestedBean bean, @NotNull String someProperty);
}

Реализация услуги:

@Service
public class TestedBeanServiceImpl implements TestedBeanService {

    @Override
    public void setBeanProperty(TestedBean bean, String someProperty) {
        bean.setSomeProperty(someProperty);
    }
}
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
5
0
3 091
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Почему здесь не поднят ConstraintViolationException? Свойство bean-компонента имеет аннотацию @NotNull, сам bean-компонент является @Validated, а сигнатура метода требует bean-компонента @Valid.

Аннотации сами по себе ничего не значат, их надо как-то обрабатывать. В этом случае аннотация @Validated обрабатывается Spring для своих компонентов. Тест не является bean-компонентом Spring, поэтому инфраструктура не рассматривает аннотации, связанные с валидацией, поэтому не является исключением.

Даже если тест был Spring Bean, подход может не работать из коробки. Подробнее см. этот вопрос.

Есть ли простой способ вызвать это исключение в контексте моего тестового класса?

Взгляните на этот вопрос

Когда я использую аннотации проверки сигнатур методов для интерфейса службы, все работает так, как ожидалось. Я не понимаю, где разница.

Это происходит потому, что service является компонентом Spring, а test — нет. Когда вызывается метод в service, он перехватывается MethodValidationInterceptor, что не относится к тесту.

Хорошо. Таким образом, мои объекты проксируются, а прокси занимаются проверкой. Я обнаружил некоторые ограничения, но я думаю, что они будут направлять мой код: - Я использую аннотации проверки для свойств своих компонентов и могу проверить их с помощью Validator - Мне не удается активировать аннотации проверки для сеттеров моих компонентов - Я могу поставить ConstraintValidationException своим методам обслуживания, если я использую аннотации проверки в его методе интерфейса. При непосредственном использовании объекта это не работает. Итак, я буду использовать аннотации свойств для своих bean-компонентов и аннотации методов для своих сервисов. спасибо

EricC-59 24.12.2020 11:24

Другие вопросы по теме