How to test validation annotations of a class using JUnit?

后端 未结 9 1118
盖世英雄少女心
盖世英雄少女心 2020-12-07 17:29

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 s

相关标签:
9条回答
  • 2020-12-07 18:10

    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>
    
    0 讨论(0)
  • 2020-12-07 18:11
    import javax.validation.ConstraintViolation;
    import javax.validation.Validation;
    import javax.validation.Validator;
    import javax.validation.ValidatorFactory;
    import static org.junit.Assert.assertFalse;
    import static org.junit.Assert.assertTrue;
    import org.junit.Before;
    import org.junit.Test;
    
    public class ValidationTest {
    
        private Validator validator;
    
        @Before
        public void init() {
    
            ValidatorFactory vf = Validation.buildDefaultValidatorFactory();
            this.validator = vf.getValidator();
    
        }
    
        @Test
        public void prereqsMet() {
            Workshop validWorkshop = new Workshop(2, 2, true, 3);
            Set<ConstraintViolation<Workshop>> violations = this.validator.validate(validWorkshop);
            assertTrue(violations.isEmpty());
        }  
    }
    

    Strictly speaking it is not a unit test, rather an Integration Test. In Unit Test you would like to test the validator logic only, without any dependencies to the SPI.

    https://www.adam-bien.com/roller/abien/entry/unit_integration_testing_the_bean

    0 讨论(0)
  • 2020-12-07 18:14

    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("jack@yahoo.com", true);
    }
    
    @Test
    public void testNoUpperCase() throws NoSuchFieldException {
        emailRegex("Jack@yahoo.com", false);
    }
    
    0 讨论(0)
提交回复
热议问题