I am trying to test a method of my controller in a Spring Boot application. This is a post endpoint, which gets an id in a request and it passes on this id to a service:
@Slf4j
@Controller
public class AdministrationController {
private final AdministrationService administrationService;
@Autowired
public AdministrationController(AdministrationService administrationService) {
this.administrationService = administrationService;
}
@PostMapping("/administration")
public @ResponseBody ResponseEntity<String> deleteByMessageId(String id) {
return new ResponseEntity<>(administrationService.deleteMessageById(id), HttpStatus.OK);
}
}
The test for this method of the controller:
RunWith(SpringRunner.class)
@WebMvcTest(AdministrationController.class)
public class AdministrationControllerTest {
@Autowired
private MockMvc mvc;
@MockBean
private AdministrationService service;
@Test
public void
deleteByMessageId_whenCalled_thenServiceMethodIsCalledWithRequestParameters() throws Exception {
Object randomObj = new Object() {
public final String id = "1234";
};
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(randomObj);
MvcResult result = mvc.perform(
post("/administration")
.contentType(MediaType.APPLICATION_JSON)
.content(json))
.andExpect(status().isOk())
.andReturn();
verify(service, times(1)).deleteMessageById("1234");
}
}
When I run this test, the post request is executed, but with an empty body:
MockHttpServletRequest:
HTTP Method = POST
Request URI = /administration
Parameters = {}
Headers = {Content-Type=[application/json]}
Body = <no character encoding set>
Session Attrs = {}
It seems, even though I set the content in my test, it does not appear in the request I am sending. And, indeed, the test fails:
Argument(s) are different! Wanted: "1234"
Actual invocation has different arguments: null
What am I missing here? How can I set the request body with MockMvc?
MockMvc provides support for Spring MVC testing. It encapsulates all web application beans and makes them available for testing. We'll initialize the mockMvc object in the @BeforeEach annotated method, so that we don't have to initialize it inside every test.
Technically speaking, tests using MockMvc are in the boundaries between unit and integration tests. They aren't unit tests because endpoints are tested in integration with a Mocked MVC container with mocked inputs and dependencies.
Typically @WebMvcTest is used in combination with @MockBean or @Import to create any collaborators required by your @Controller beans. If you are looking to load your full application configuration and use MockMVC, you should consider @SpringBootTest combined with @AutoConfigureMockMvc rather than this annotation.
The MockMvcBuilders. standaloneSetup allows to register one or more controllers without the need to use the full WebApplicationContext .
Try to use .characterEncoding("utf-8"))
:
MvcResult result = mvc.perform(post("/administration")
.contentType(MediaType.APPLICATION_JSON)
.content(json)
.characterEncoding("utf-8"))
.andExpect(status().isOk())
.andReturn();
Another option (that is inspired by @stelios-anastasakis answer) is to provide character encoding within the Content-Type
header:
MvcResult result = mvc.perform(post("/administration")
.contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)
.content(json)
.andExpect(status().isOk())
.andReturn();
Note that we use MediaType.APPLICATION_JSON_UTF8_VALUE
instead of MediaType.APPLICATION_JSON
here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With