I am testing request validation in Spring RestController with the help of integration testing and MockMvc.
ControllerTest.java
@ExtendWith(MockitoExtension.class)
@SpringBootTest(classes = Controller.class)
@AutoConfigureMockMvc(addFilters = false)
class ControllerTest {
private ObjectMapper objectMapper;
@MockBean
private Service service;
@Autowired
private MockMvc mockMvc;
@BeforeEach
void setUp() {
objectMapper = new ObjectMapper();
}
@Test
void createOrAdd_shouldReturnErrorResponseOnInvalidInput() throws Exception {
Request request = Request.builder()
.name("name<script>")
.primaryEmail("[email protected]")
.build();
mockMvc.perform(MockMvcRequestBuilders.post("/api/create")
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(objectMapper.writeValueAsString(request))
.characterEncoding("utf-8"))
.andExpect(MockMvcResultMatchers.status().isBadRequest());
}
}
Controller.java :
@Slf4j
@RestController
public class Controller {
private final Service service;
public Controller(Service service) {
this.service = service;
}
@PostMapping(value = "/api/create", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<GenericResponse<Response>> createOrAdd(@RequestBody @Valid Request request, Errors errors) {
GenericResponse<Response> genericResponse = new GenericResponse<>();
try {
if (errors.hasErrors()) {
throw new RequestParamsException(errors.getAllErrors());
}
Response response = service.createOrAdd(request);
genericResponse.setData(response);
return ResponseEntity.ok().body(genericResponse);
} catch (RequestParamsException ex) {
genericResponse.setErrors(ex.getErrors());
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(genericResponse);
}
}
Error :
WARN 17304 --- [ main] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/json;charset=utf-8' not supported]
MockHttpServletRequest:
HTTP Method = POST
Request URI = /api/create
Parameters = {}
Headers = [Content-Type:"application/json;charset=utf-8", Accept:"application/json", Content-Length:"162"]
Body = {"name":"name<script>alert(1)</script>","primary_email_address":"[email protected]"}
Session Attrs = {}
Handler:
Type = com.org.controller.Controller
Method = com.org.controller.Controller#createOrAdd(Request, Errors)
Async:
Async started = false
Async result = null
Resolved Exception:
Type = org.springframework.web.HttpMediaTypeNotSupportedException
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 415
Error message = null
Headers = [Accept:"application/octet-stream, text/plain, application/xml, text/xml, application/x-www-form-urlencoded, application/* xml, multipart/form-data, multipart/mixed, */*"]
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
java.lang.AssertionError: Status expected:<400> but was:<415>
Expected :400
Actual :415
I have used the correct Content-Type
and Accept
Headers while making a call in Test.java
using mockMvc
, but still it's giving HttpMediaTypeNotSupportedException. Tried many combinations in Accept
and Content-Type
but still not working.
I have read many SO questions related to this exception, but couldn't find what's the issue here. Still not able to figure out why it's saying HttpMediaTypeNotSupportedException.
Update : After removing addFilters = false
as suggested, not able to find the handler itself.
MockHttpServletRequest:
HTTP Method = POST
Request URI = /api/create
Parameters = {}
Headers = [Content-Type:"application/json;charset=utf-8", Accept:"application/json", Content-Length:"162"]
Body = {"name":"name<script>alert(1)</script>","primary_email_address":"[email protected]"}
Session Attrs = {org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN=org.springframework.security.web.csrf.DefaultCsrfToken@7a687d8d}
Handler:
Type = null
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 403
Error message = Forbidden
Headers = [X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY"]
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
java.lang.AssertionError: Status expected:<400> but was:<403>
Expected :400
Actual :403
CodePudding user response:
I think you are missing @WebMvcTest(controllers = Controller.class)
CodePudding user response:
You need to drop the addFilters = false
from your AutoConfiguration annotation
@AutoConfigureMockMvc(addFilters = false)
should just be
@AutoConfigureMockMvc
Some of those filters actually determine how to marshal the input and output of the request handlers.
If you have Security enabled, you'll want to replaces the three annotations at your class level with this:
@ExtendWith(MockitoExtension.class)
@WebMvcTest(controllers = Controller.class, excludeAutoConfiguration = SecurityAutoConfiguration.class)
@AutoConfigureMockMvc