如何使用JUnit测试类的验证注释?

Jac*_*ack 29 java junit

我需要测试验证注释,但看起来它们不起作用.我不确定JUnit是否也正确.目前,测试将通过,但您可以看到指定的电子邮件地址是错误的.

JUnit的

public static void testContactSuccess() {
        Contact contact = new Contact();
        contact.setEmail("Jackyahoo.com");
        contact.setName("Jack");
        System.err.println(contact);
    }
Run Code Online (Sandbox Code Playgroud)

要测试的类

public class Contact {

    @NotNull
    @Size(min = 1, max = 10)
    String name;

    @NotNull
    @Pattern(regexp="[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\."
            +"[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@"
            +"(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?",
                 message="{invalid.email}")
    String email;

    @Digits(fraction = 0, integer = 10)
    @Size(min = 10, max = 10)
    String phone;

    getters and setters

}
Run Code Online (Sandbox Code Playgroud)

eis*_*eis 62

对方回答说,"注释不自己做任何事情,你需要使用一个验证器来处理对象"是正确的,然而,答案没有对如何使用验证器实例,这对我来说是这样做的工作指令我真正想要的是什么.

Hibernate-validator是这种验证器的参考实现.您可以非常干净地使用它:

import static org.junit.Assert.assertFalse;

import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

public class ContactValidationTest {

    private Validator validator;

    @Before
    public void setUp() {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        validator = factory.getValidator();
    }
    @Test
    public void testContactSuccess() {
        // I'd name the test to something like 
        // invalidEmailShouldFailValidation()

        Contact contact = new Contact();
        contact.setEmail("Jackyahoo.com");
        contact.setName("Jack");
        Set<ConstraintViolation<Contact>> violations = validator.validate(contact);
        assertFalse(violations.isEmpty());
    }
}
Run Code Online (Sandbox Code Playgroud)

这假设您有验证器实现和junit作为依赖项.

使用Maven pom的依赖项示例:

<dependency>
    <groupId>org.hibernate</groupId>
    <version>5.2.4.Final</version>
    <artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>
Run Code Online (Sandbox Code Playgroud)

  • 如果使用 Spring,则可以注入 Validator,如下所示:`@Autowired private Validator validator;` (4认同)

Ooz*_*lly 12

使用以下方法测试验证注释的简单方法javax

Validator在类级别声明:

private final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
Run Code Online (Sandbox Code Playgroud)

然后在您的测试中,只需在object您需要验证时调用它,并使用exception您要验证的内容:

Set<TheViolation<TheClassYouAreValidating> violations = validator.validate(theInstanceOfTheClassYouAreValidating);
Run Code Online (Sandbox Code Playgroud)

然后只是assert预期的违规次数:

assertThat(violations.size()).isEqualTo(1);
Run Code Online (Sandbox Code Playgroud)

您需要将此添加到您的依赖项 ( gradle):

compile group: 'javax.validation', name: 'validation-api', version: '2.0.1.Final'

  • 难道你不需要在类路径中也有一个验证器实现,而不仅仅是 api 吗? (3认同)

Bev*_*ynQ 6

注释本身不会做任何事情,您需要使用验证器来处理对象。

您的测试需要运行一些这样的代码

    Configuration<?> configuration = Validation
        .byDefaultProvider()
        .providerResolver( new MyResolverStrategy() ) <== this is where is gets tricky
        .configure();
    ValidatorFactory factory = configuration.buildValidatorFactory();

    Contact contact = new Contact();
    contact.setEmail("Jackyahoo.com");
    contact.setName("Jack");
    factory.getValidator().validate(contact); <== this normally gets run in the background by whatever framework you are using
Run Code Online (Sandbox Code Playgroud)

但是,您在这里面临的困难是这些都是接口,您将需要实现才能进行测试。您可以自己实施,也可以找到要使用的。

但是,您想问自己的问题是您要测试什么?That the hibernate validator works the way it should?要么that your regex is correct?

如果这是我,我将认为验证器可以工作(即其他人对此进行了测试),并专注于正则表达式。这将涉及一些反思

public void emailRegex(String email,boolean validates){

    Field field = Contact.class.getDeclaredField("email");
    javax.validation.constraints.Pattern[] annotations = field.getAnnotationsByType(javax.validation.constraints.Pattern.class);
    assertEquals(email.matches(annotations[0].regexp()),validates);

}
Run Code Online (Sandbox Code Playgroud)

然后您可以定义您的testMethods,它们是实际的单元测试

@Test
public void testInvalidEmail() throws NoSuchFieldException {
    emailRegex("Jackyahoo.com", false);
}

@Test
public void testValidEmail() throws NoSuchFieldException {
    emailRegex("jack@yahoo.com", true);
}

@Test
public void testNoUpperCase() throws NoSuchFieldException {
    emailRegex("Jack@yahoo.com", false);
}
Run Code Online (Sandbox Code Playgroud)


Laz*_*azR 5

首先感谢@Eis的回答,它对我有帮助。这是一个失败测试的好方法,但我想要更多“栩栩如生”的行为。在运行时会抛出异常,所以我想出了这个:

/**
 * Simulates the behaviour of bean-validation e.g. @NotNull
 */
private void validateBean(Object bean) throws AssertionError {
    Optional<ConstraintViolation<Object>> violation = validator.validate(bean).stream().findFirst();
    if (violation.isPresent()) {
        throw new ValidationException(violation.get().getMessage());
    }
}
Run Code Online (Sandbox Code Playgroud)

拥有一个经过验证的实体:

@Data
public class MyEntity {

@NotBlank(message = "Name cannot be empty!")
private String name;

}
Run Code Online (Sandbox Code Playgroud)

在测试中,您可以传递具有无效属性的实例并期望出现异常:

private Validator validator;

@Before
public void setUp() {
    ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
    validator = factory.getValidator();
}

@Test(expected = ValidationException.class)
public void testValidationWhenNoNameThenThrowException() {
    validateBean(new Entity.setName(""));
}
Run Code Online (Sandbox Code Playgroud)


vik*_*kas -1

我认为验证会在调用预定义方法后起作用,这些方法通常由容器完成,大多数情况下不会在调用对象的 setter 之后立即完成。从您共享的文档链接:

> 默认情况下,持久性提供程序将在 PrePersist、PreUpdate 和 PreRemove 生命周期事件发生后立即自动对具有使用 Bean Validation 约束注释的持久字段或属性的实体执行验证。