Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Controller testing with MockMvc post method

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?

like image 923
handris Avatar asked Apr 21 '18 13:04

handris


People also ask

What is the use of MockMvc in spring boot?

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.

Is MockMvc integration 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.

What is the use of @WebMvcTest?

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.

What is MockMvcBuilders standaloneSetup?

The MockMvcBuilders. standaloneSetup allows to register one or more controllers without the need to use the full WebApplicationContext .


2 Answers

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();
like image 197
stelios.anastasakis Avatar answered Sep 19 '22 16:09

stelios.anastasakis


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.

like image 21
Slava Semushin Avatar answered Sep 18 '22 16:09

Slava Semushin