Reputation: 11610
I have custom validator that uses a service
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();
}
My goal is to use it inside of a controller MVC test, with a mocked service, to control validation output.
In order to test it within a controller request, I tried to use @WebMvcTest. But then security pops in, giving me 403 everywhere. In order to disable it I added:
@AutoConfigureMockMvc(addFilters = false) // to avoid security
@WebMvcTest(ProdutDataController.class)
class EditCompanyRegistryDataControllerTest {
@MockBean
private ProductService pkdService;
@Autowired
private MockMvc mvc;
But now Spring ignores also form validation, returning status 200/201 instead of 400, when validation should be triggered.
Question:
1 Is there a way to disable security only, without the validation in MVC tests?.
2 Is it possible to register custom validators using MockMvcBuilders.standaloneSetup(...) builder? This way I could ignore spring context, and focus on standalone setup with mocks.
Upvotes: 0
Views: 1614
Reputation: 21720
Use Spring Security Test Support
There really isn't a good way to disable just Spring Security because that is not recommend. Instead it is recommended to use Spring Security's MockMvc test support. This ensures that your tests are aligned with your configuration.
With Spring Boot, the integration with Spring Security is automatically added to the @Autowired MockMvc
instance. Then you have the choice of using either Annotations or RequestProcessor to run your test.
Using Annotations:
@Test
@WithMockUser
public void requestProtectedUrlWithUser() throws Exception {
mvc
.perform(get("/"))
...
}
This will run as the user with username "user" and role "ROLE_USER". You can also override the attributes with something like: @WithMockUser(username="rob", roles="ADMIN")
.
Alternatively, you can also use a RequestPostProcessor
.
mvc
.perform(get("/").with(user("user")))
You can also override the default roles and password:
mvc
.perform(get("/admin").with(user("admin").password("pass").roles("USER","ADMIN")))
For more details including additional customization, best practices, etc refer to the links I provided.
Standalone Setup
The standalone setup doesn't configure anything automatically (including validation and security). You an explicitly configure the validator, but you must ensure it is the same instance as that is configured in your application.
One way to do this is to @Autowire
the Validator
instance.
@SpringBootTest
class TheTest {
@Autowired
Validator validator;
@Test
void standaloneTest() {
MockMvc mvc = MockMvcBuilders
.standaloneSetup(new MyController())
.setValidator(this.validator).build();
}
Alternatively, you can create your own instance of the Validator
directly. This complicates things as you must keep this in sync with how your Validator
is created in Spring. The default is to use OptionalValidatorFactoryBean
:
MockMvc mvc = MockMvcBuilders
.standaloneSetup(new MyController())
.setValidator(new OptionalValidatorFactoryBean())
.build();
Upvotes: 1