Spring 5 MVC测试自定义验证器

问题描述

我有使用服务的自定义验证程序

public class ProductCodeValidator implements ConstraintValidator<ProdutCode,Set<String>> {

    ...
    @Override
    public boolean isValid(Set<String> pkdCodes,ConstraintValidatorContext context) {
        return pkdCodes != null && service.count(pkdCodes) == pkdCodes.size();
    }

我的目标是在带有模拟服务的控制器MVC测试中使用它来控制验证输出。

为了在控制器请求中对其进行测试,我尝试使用@WebMvcTest。但是随后出现了安全问题,使我到处都是403。为了禁用它,我添加了:

@AutoConfigureMockMvc(addFilters = false) // to avoid security
@WebMvcTest(ProdutDataController.class)
class EditCompanyRegistryDataControllerTest {

    @MockBean
    private ProductService pkdService;
 
    @Autowired
    private MockMvc mvc;

但是现在Spring也会忽略表单验证,在触发验证时会返回状态200/201而不是400。

问题:

1是否有一种方法可以只禁用安全性,而无需在MVC测试中进行验证?。

2是否可以使用MockMvcBuilders.standaloneSetup(...)构建器注册自定义验证器?这样,我可以忽略spring上下文,而专注于使用模拟进行独立设置。

解决方法

使用Spring Security测试支持

确实没有一种仅禁用Spring Security的好方法,因为不建议这样做。相反,建议使用Spring Security的MockMvc test support。这样可以确保您的测试与您的配置保持一致。

使用Spring Boot,与Spring Security的集成会自动添加到@Autowired MockMvc实例中。然后,您可以选择使用AnnotationsRequestProcessor来运行测试。

使用注释:

@Test
@WithMockUser
public void requestProtectedUrlWithUser() throws Exception {
    mvc
        .perform(get("/"))
        ...
}

这将以用户名“ user”和角色“ ROLE_USER”的用户身份运行。您也可以使用类似@WithMockUser(username="rob",roles="ADMIN")的属性来覆盖属性。

或者,您也可以使用RequestPostProcessor

mvc
    .perform(get("/").with(user("user")))

您还可以覆盖默认角色和密码:

mvc
    .perform(get("/admin").with(user("admin").password("pass").roles("USER","ADMIN")))

有关更多详细信息(包括其他自定义,最佳做法等),请参阅我提供的链接。

独立设置

独立设置不会自动配置任何内容(包括验证和安全性)。您明确配置了验证器,但必须确保它与应用程序中配置的实例相同。

一种实现方法是@Autowire Validator实例。

@SpringBootTest
class TheTest {

    @Autowired
    Validator validator;

    @Test
    void standaloneTest() {
        MockMvc mvc = MockMvcBuilders
                .standaloneSetup(new MyController())
                .setValidator(this.validator).build();
    }

或者,您可以直接创建自己的Validator实例。这使事情变得复杂,因为您必须使其与在Spring中创建Validator的方式保持同步。默认设置为使用OptionalValidatorFactoryBean

MockMvc mvc = MockMvcBuilders
            .standaloneSetup(new MyController())
            .setValidator(new OptionalValidatorFactoryBean())
            .build();

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...