How to test validation annotations of a class using JUnit?

后端 未结 9 1134
盖世英雄少女心
盖世英雄少女心 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条回答
  •  Happy的楠姐
    2020-12-07 18:06

    Here my way to unit test my objects with fields annotated with some javax.validation.constraints constraints.
    I will give an example with Java 8, JPA entity, Spring Boot and JUnit 5 but the overall idea is the same whatever the context and the frameworks :
    We have a nominal scenario where all fields are correctly valued and generally multiple error scenarios where one or more fields are not correctly valued.

    Testing field validation is not a particularly hard thing.
    But as we have many fields to validate, the tests may become more complex, we can forget some cases, introducing side effects in tests between two cases to validate or simply introduce duplication.
    I will give my mind about how to avoid that.

    In the OP code, we will suppose that the 3 fields have a NotNull constraint. I think that under 3 distinct constraints, the pattern and its value are less visible.

    I wrote first a unit test for the nominal scenario :

    import org.junit.jupiter.api.Test;
    
    @Test
    public void persist() throws Exception {       
        Contact contact = createValidContact();
    
        // action
        contactRepository.save(contact);       
        entityManager.flush();
        entityManager.clear(); 
        // assertion on the id for example
         ...
    }
    

    I extract the code to create a valid contact into a method as it will be helpful for no nominal cases :

    private Contact createValidContact(){
       Contact contact = new Contact();
       contact.setEmail("Jackyahoo.com");
       contact.setName("Jack");
       contact.setPhone("33999999");   
       return contact;     
    }
    

    Now I write a @parameterizedTest with as fixture source a @MethodSource method :

    import org.junit.jupiter.params.ParameterizedTest;
    import org.junit.jupiter.params.provider.MethodSource;
    import javax.validation.ConstraintViolationException;
    
    @ParameterizedTest
    @MethodSource("persist_fails_with_constraintViolation_fixture")
    void persist_fails_with_constraintViolation(Contact contact ) {
        assertThrows(ConstraintViolationException.class, () -> {
            contactRepository.save(contact);
            entityManager.flush();
        });
    }
    

    To compile/run @parameterizedTest, think of adding the required dependency that is not included in the junit-jupiter-api dependency :

    
        org.junit.jupiter
        junit-jupiter-params
        ${junit-jupiter.version}
        test
    
    

    In the fixture method to create invalid contacts, the idea is simple. For each case, I create a new valid contact object and I set incorrectly only the field to validate concerned to.
    In this way, I ensure that no side effect between cases are present and that each case provokes itself the expected validation exception as without the field set the valid contact was successful persisted.

    private static Stream persist_fails_with_constraintViolation_fixture() {
    
        Contact contactWithNullName = createValidContact();
        contactWithNullName.setName(null);
    
        Contact contactWithNullEmail = createValidContact();
        contactWithNullEmail.setEmail(null);
    
        Contact contactWithNullPhone = createValidContact();
        contactWithNullPhone.setPhone(null);             
    
        return Stream.of(contactWithNullName, contactWithNullEmail,  contactWithNullPhone);
    }
    

    Here is the full test code :

    import org.junit.jupiter.params.ParameterizedTest;
    import org.junit.jupiter.params.provider.MethodSource;
    import javax.validation.ConstraintViolationException;
    import org.junit.jupiter.api.BeforeEach;
    import org.junit.jupiter.api.Test;
    import org.junit.jupiter.api.extension.ExtendWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
    import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
    import org.springframework.test.context.junit.jupiter.SpringExtension;    
    
    @DataJpaTest
    @ExtendWith(SpringExtension.class)
    public class ContactRepositoryTest {
    
        @Autowired
        private TestEntityManager entityManager;
    
        @Autowired
        private ContactRepository contactRepository;
    
        @BeforeEach
        public void setup() {
            entityManager.clear();
        }
    
        @Test
        public void persist() throws Exception {       
            Contact contact = createValidContact();
    
            // action
            contactRepository.save(contact);       
            entityManager.flush();
            entityManager.clear(); 
            // assertion on the id for example
             ...
        }
    
        @ParameterizedTest
        @MethodSource("persist_fails_with_constraintViolation_fixture")
        void persist_fails_with_constraintViolation(Contact contact ) {
            assertThrows(ConstraintViolationException.class, () -> {
                contactRepository.save(contact);
                entityManager.flush();
            });
        }
    
        private static Stream persist_fails_with_constraintViolation_fixture() {
    
            Contact contactWithNullName = createValidContact();
            contactWithNullName.setName(null);
    
            Contact contactWithNullEmail = createValidContact();
            contactWithNullEmail.setEmail(null);
    
            Contact contactWithNullPhone = createValidContact();
            contactWithNullPhone.setPhone(null);             
    
            return Stream.of(contactWithNullName, contactWithNullEmail,  contactWithNullPhone);
        }
    }
    

提交回复
热议问题