简体   繁体   English

如何在带有验证注释的 bean 属性的测试用例中引发 ConstraintValidationException?

[英]How to raise a ConstraintValidationException in a test case for bean properties with validation annotations?

I'm trying to test that my beans have correct validation annotations.我正在尝试测试我的 bean 是否具有正确的验证注释。 I'm using spring-boot.我正在使用 spring-boot。 Here is an example test case:这是一个示例测试用例:

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

I expect the call to checkIfvalidated() and to setSomeProperty(null) to raise a ConstraintViolationException , and the tests to pass, but they both fail with:我希望调用checkIfvalidated()setSomeProperty(null)来引发ConstraintViolationException ,并且测试能够通过,但它们都失败了:

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

My pom.xml:我的 pom.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>

Why is there no ConstraintViolationException raised here?为什么这里没有引发ConstraintViolationException The bean property has a @NotNull annotation, the bean itself is @Validated and the method signature requires a @Valid bean. bean 属性有一个@NotNull注释,bean 本身是@Validated并且方法签名需要一个@Valid bean。

Is there a simple way to have that exception raised in the context of my test class?有没有一种简单的方法可以在我的测试 class 的上下文中引发该异常?

When I use validation annotations on method signatures for a service interface, everything works as expected.当我在服务接口的方法签名上使用验证注释时,一切都按预期工作。 I don't understand where is the difference.我不明白区别在哪里。

Service interface:服务接口:

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

Service implementation:服务实现:

package com.example.sandbox;

import org.springframework.stereotype.Service;

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

Test case:测试用例:

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

==> The test passes. ==> 测试通过。


Working code according to the given answer:根据给定答案的工作代码:

The test class:测试 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);
    }
}

The tested bean:被测试的bean:

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

The service interface:服务接口:

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

The service implementation:服务实现:

@Service
public class TestedBeanServiceImpl implements TestedBeanService {

    @Override
    public void setBeanProperty(TestedBean bean, String someProperty) {
        bean.setSomeProperty(someProperty);
    }
}

Why is there no ConstraintViolationException raised here?为什么这里没有引发ConstraintViolationException The bean property has a @NotNull annotation, the bean itself is @Validated and the method signature requires a @Valid bean. bean 属性有一个@NotNull注释,bean 本身是@Validated并且方法签名需要一个@Valid bean。

Annotations by themselves do not mean anything, they should be processed in some way.注释本身没有任何意义,它们应该以某种方式处理。 In this case the @Validated annotation is processed by Spring for its beans .在这种情况下,@Validated 注释由@Validated为其 beans处理。 The test is not a Spring bean, so the framework does not look at the annotations related to valdidation, hence no exception.该测试不是 Spring bean,因此框架不查看与验证相关的注释,因此也不例外。

Even if the test were a Spring Bean, the approach may not work out of the box.即使测试是 Spring Bean,该方法也可能无法开箱即用。 See this question for details.有关详细信息,请参阅问题。

Is there a simple way to have that exception raised in the context of my test class?有没有一种简单的方法可以在我的测试 class 的上下文中引发该异常?

Take a look at this question看看这个问题

When I use validation annotations on method signatures for a service interface, everything works as expected.当我在服务接口的方法签名上使用验证注释时,一切都按预期工作。 I don't understand where is the difference.我不明白区别在哪里。

This happens because the service is a Spring bean, but test is not.发生这种情况是因为service是 Spring bean,但测试不是。 When a method on the service is invoked, it gets intercepted by MethodValidationInterceptor , which is not the case for testservice上的方法被调用时,它会被MethodValidationInterceptor拦截,这不是测试的情况

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM