Spring 5 MVC 测试自定义验证器

Spring 5 MVC test custom validator

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

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安全测试支持

确实没有一个很好的方法来禁用 Spring 安全性,因为不推荐这样做。相反,建议使用 Spring 安全性的 MockMvc test support。这可确保您的测试与您的配置保持一致。

使用 Spring 引导,与 Spring 安全性的集成会自动添加到 @Autowired MockMvc 实例。然后你可以选择使用 Annotations or RequestProcessor 到 运行 你的测试。

使用注释:

@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 实例。这使事情变得复杂,因为您必须使它与 Validator 在 Spring 中的创建方式保持同步。默认是使用 OptionalValidatorFactoryBean:

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