Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test validation annotations of a class using JUnit?

Tags:

java

junit

I need to test the validation annotations but it looks like they do not work. I am not sure if the JUnit is also correct. Currently, the test will be passed but as you can see the specified email address is wrong.

JUnit

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

Class to be tested

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

}
like image 824
Jack Avatar asked Mar 16 '15 05:03

Jack


People also ask

Which annotations is used for validation?

The @Valid annotation applies validation rules on the provided object. The BindingResult interface contains the result of validation.

Which annotations can be used to write test cases in JUnit?

JUnit provides an annotation called @Test, which tells the JUnit that the public void method in which it is used can run as a test case. To execute multiple tests in a specified order, it can be done by combining all the tests in one place. This place is called as the test suites.


3 Answers

The other answer saying that "the annotations do not do anything by themselves, you need to use a Validator to process the object" is correct, however, the answer lacks working instructions on how to do it using a Validator instance, which for me was what I really wanted.

Hibernate-validator is the reference implementation of such a validator. You can use it quite cleanly like this:

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

This assumes you have validator implementation and junit as dependencies.

Example of dependencies using 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> 
like image 136
eis Avatar answered Sep 21 '22 12:09

eis


A simple way to test validation annotations using javax:

Declare the Validator at Class level:

private final Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); 

Then in your test simply call it on the object you require validation on, with what exception you are validating:

Set<TheViolation<TheClassYouAreValidating> violations = validator.validate(theInstanceOfTheClassYouAreValidating); 

Then simply assert the number of expected violations:

assertThat(violations.size()).isEqualTo(1); 

You will need to add this to your dependencies (gradle):

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

like image 29
Oozeerally Avatar answered Sep 19 '22 12:09

Oozeerally


The annotations do not do anything by themselves, you need to use a Validator to process the object.

Your test needs to run some code like this

    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

However, the difficulty you face here are these are all interfaces, you will need implementations to be able to test. You could implement it yourself or find one to use.

However the question you want to ask yourself is what are you trying to test? That the hibernate validator works the way it should? or that your regex is correct?

If this was me I would assume that the Validator works(ie someone else tested that) and focus on the regex. Which would involve a bit of reflection

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

}

then you can define your testMethods which are actual unit tests

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

@Test
public void testValidEmail() throws NoSuchFieldException {
    emailRegex("[email protected]", true);
}

@Test
public void testNoUpperCase() throws NoSuchFieldException {
    emailRegex("[email protected]", false);
}
like image 36
BevynQ Avatar answered Sep 19 '22 12:09

BevynQ