【问题标题】:@Valid does not trigger validation in @Repository@Valid 不会在 @Repository 中触发验证
【发布时间】:2020-02-21 23:20:27
【问题描述】:

我正在编写单元测试来检查输入验证是否在我的 Spring 存储库中有效,但它看起来不像。

为了简单起见,我有一个 Repository 类:

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

这使用以下模型类:

@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;
}

所以我写了一个这样的单元测试,期望它抛出一些我可以断言的异常:

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

但它只是运行,只输出调试消息(我在这个问题中遗漏了)。 如何强制执行验证?如果可能,我想避免在存储库的每个方法中显式调用验证器。

我在网上看到了很多我尝试复制的示例(从 Baeldung 到 DZone,当然在这个网站上有很多问题,包括 this interesting one),但仍然不成功。我错过了什么?

【问题讨论】:

    标签: java spring-boot unit-testing bean-validation jedis


    【解决方案1】:

    看起来你需要实现一个integration test,如果你想使用repository,这样javax.validation.ConstraintViolationException就会通过显示must not be blank被抛出,但如果你只想测试那些验证,那么你将不得不测试通过以下方式使用验证器:

    1.- 添加如下依赖:

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

    2.- 为Customer 字段添加自定义验证测试

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

    【讨论】:

    • 我应该改变什么以使我的班级成为integration test?我得到了检查每个验证的单独测试,但我不明白你答案的开头
    • 您需要一个 datasource 加载您可以使用以下 embedded database 来测试 @AutoConfigureEmbeddedDatabase 注释,让我通过使用 integration test stackoverflow.com/a/49011982/10426557 分享一个答案stackoverflow.com/a/49011982/10426557 让我知道这是否对您有帮助.谢谢,亲切的问候。
    • 好的,我会测试它。有没有办法只模拟我的数据库连接并执行其余方法,包括@Valid 检查?我不明白为什么拥有一个“真正的”数据库(尽管在内存中)是解决方案的一部分......
    • mocking 不是一个真实的环境,那么如果你想抛出 ConstraintViolationException 以便你可以验证它的内容,那么应该创建一个 embedded database 以模拟 real datasource
    猜你喜欢
    • 2018-04-14
    • 1970-01-01
    • 2021-12-23
    • 1970-01-01
    • 1970-01-01
    • 2016-10-03
    • 1970-01-01
    • 2015-06-23
    • 2019-04-08
    相关资源
    最近更新 更多