@Valid does not trigger validation in @Repository

AdrienW :

I'm writing unit tests to check if the input validation works in my Spring Repository, but it doesn't look like it does.

Keeping it simple, I have a Repository class:

@Repository
public class CustomerRepository {
    // Java client for Redis, that I extend as JedisConnector in order to make it a Bean
    private Jedis jedis;

    @Autowired
    public CustomerRepository(JedisConnector jedis) {
        this.jedis = jedis;
    }

    private <S extends Customer> S save(@Valid S customer) throws CustomerException {
        try {
            this.jedis.set(...);  // writing to Redis (mocked in test)
            return customer;
        } catch (JsonProcessingException e) {
            throw new CustomerException(e.toString());
        }
    }
}

This uses the following model class:

@AllArgsConstructor
@NoArgsConstructor
@Data // from Lombok
public class Customer {
    @Email(message = "Email must be valid.")
    private String identifier;

    @NotBlank(message = "Password cannot be null or empty string.")
    private String password;

    @URL(message = "URL must be a url.")
    private String url;
}

So I wrote a unit test like this, expecting it to throw some exception that I could assert:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {JedisConnector.class})
public class CustomerRepositoryTest {
    // Cannot autowire because dependent bean needs to be configured
    private CustomerRepository customerRepository;

    @MockBean
    JedisConnector jedisConnector;

    @Before
    public void setUp() {
        // Configure Mock JedisConnector
        MockitoAnnotations.initMocks(this);
        Mockito.when(jedisConnector.select(anyInt())).thenReturn("OK");

        // Manually wire dependency
        customerRepository = new CustomerRepository(jedisConnector);
    }


    @Test
    public void saveShouldFailOnInvalidInput() throws CustomerException {
        Mockito.when(jedisConnector.set(anyString(), anyString())).thenReturn("OK");
        // Blatantly invalid input
        Customer customer = new Customer("testemail", "", "testurl");
        customerRepository.save(customer);
    }
}

But it just runs through, only outputting debug messages (that I left out in this question). How do I enforce the validation? If possible, I'd like to avoid calling a validator explicitely in each method of the repository.

I've seen many examples online that I've tried to reproduce (From Baeldung to DZone, with of course a lot of questions on this very website, including this interesting one), still unsuccessful. What am I missing?

Jonathan JOhx :

Looks like you need to implement a integration test if you want to use repository via so that javax.validation.ConstraintViolationException is thrown by showing must not be blank but if you want to test only those validations then you will have to test by using a validator by following way:

1.- Add the following dependency:

<dependency> 
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.0.13.Final</version>
</dependency> 

2.- Add a custom validation tests for the Customer fields

import javax.validation.Validation;
import javax.validation.Validator;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringRunner;

import static org.assertj.core.api.Assertions.assertThat;

@RunWith(SpringRunner.class)
public class CustomerValidationTest {

    private Validator validator;

    @Before
    public void setupValidatorInstance() {
        validator = Validation.buildDefaultValidatorFactory().getValidator();
    }

    @Test
    public void whenNotEmptyPassword_thenNoConstraintViolations() {
        Customer customer = new Customer();
        customer.setPassword("");
        Set<ConstraintViolation<Customer>> violations = validator.validate(customer);

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

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=323331&siteId=1