问题描述
我有使用服务的自定义验证程序
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
实例中。然后,您可以选择使用Annotations或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
实例。这使事情变得复杂,因为您必须使其与在Spring中创建Validator
的方式保持同步。默认设置为使用OptionalValidatorFactoryBean
:
MockMvc mvc = MockMvcBuilders
.standaloneSetup(new MyController())
.setValidator(new OptionalValidatorFactoryBean())
.build();