Spring MockMVC - 如何模拟在 Controller 外部运行的自定义验证器

标签 spring validation unit-testing spring-test spring-test-mvc

@UsernameAlreadyExists
private String username;

我创建了一个自定义验证器,以确保在提交帐户创建表单时应用程序捕获重复的用户名。

当我使用 MockMVC 对帐户创建 Controller 进行单元测试时,由于验证器依赖于服务而失败,因此我得到了空指针异常。

如何模拟验证器或该验证器所依赖的服务? 我无法弄清楚如何使其工作,因为 Controller 不明确依赖于验证器,它在 Controller 外部运行。

最佳答案

使用“standaloneSetup”进行测试(无需加载整个 Spring 上下文)时,验证由 SpringWebConstraintValidatorFactory 上的框架调用在内部触发。为了连接到该流程,您需要在“mockMvc”中设置 SpringWebConstraintValidatorFactory 的新实例。
不幸的是,没有一种简单干净的方法可以做到这一点。您必须子类化 SpringWebConstraintValidatorFactory 并在 LocalValidatorFactoryBean 中设置实例,而该实例又可以在 mockMvc 中设置。但是 LocalValidatorFactoryBean 将需要 ApplicationContext。这是一个例子:



    public class TestConstrainValidationFactory extends SpringWebConstraintValidatorFactory {

        private final WebApplicationContext ctx;

        private boolean isValid = false;

        public TestConstrainValidationFactory(WebApplicationContext ctx) {
            this.ctx = ctx;
        }

        @Override
        public < T extends ConstraintValidator<?, ?>> T getInstance(Class key) {
            ConstraintValidator instance = super.getInstance(key);
            if (instance instanceof DeviceValidator) {
                DeviceValidator deviceValidator = (DeviceValidator) instance;
                deviceValidator.setYourAutowiredField((String id, String type) -> isValid); //change that to suit your needs
                instance = deviceValidator;
            }
            return (T) instance;
        }

        @Override
        protected WebApplicationContext getWebApplicationContext() {
            return ctx;
        }

    }

将其连接到mockMvc的示例



    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringApplicationConfiguration(classes = MockServletContext.class)
    @WebAppConfiguration()
    public class DevicesControllerTest {
        @Autowired
        private MockServletContext servletContext;
        @InjectMocks
        private DevicesController devicesController;
        private TestConstrainValidationFactory constraintFactory;

        @Before
        public void setUp() {
            MockitoAnnotations.initMocks(this);

            final GenericWebApplicationContext context = new GenericWebApplicationContext(servletContext);
            final ConfigurableListableBeanFactory beanFactory = ((ConfigurableApplicationContext) context).getBeanFactory();
            beanFactory.registerSingleton(DeviceValidator.class.getCanonicalName(), new DeviceValidator());
            context.refresh();

            LocalValidatorFactoryBean validatorFactoryBean = new LocalValidatorFactoryBean();
            validatorFactoryBean.setApplicationContext(context);
            constraintFactory = new TestConstrainValidationFactory(context);
            validatorFactoryBean.setConstraintValidatorFactory(constraintFactory);
            validatorFactoryBean.setProviderClass(HibernateValidator.class);
            validatorFactoryBean.afterPropertiesSet();

            this.mockMvc = MockMvcBuilders
                    .standaloneSetup(devicesController)
                    .setValidator(validatorFactoryBean)
                    .setHandlerExceptionResolvers()
                    .build();
        }
    }

一旦获得它,ReflectionTestUtils.setField(constraintFactory, "isValid", false); 将按预期工作,您可以通过工厂在验证器中设置字段。
查看问题上下文 spring-projects/spring-test-mvc/issues :

关于Spring MockMVC - 如何模拟在 Controller 外部运行的自定义验证器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23161752/

相关文章:

java - 使用多个参数过滤数据的最有效方法?

java - 在存储库中保存实体不起作用 SPRING

java - 依赖注入(inject) servlet 监听器

ios - 验证期间的 iTunes 连接架构问题

java - JUnit - 使用参数中的对象测试类实例化

java - 投影到类时,使用 @Query 的投影无法按预期工作

java - Hibernate 验证——与其他对象比较

javascript - 无法在 mozilla firefox 上验证

Java 单元测试完整性指示工具?

java - OkHttp MockWebServer 重启时接受连接失败