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();
我有使用服务的自定义验证器
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();