eln
eln

Reputation: 93

spring mock mvc perform post request body is missing : error 400

I try to mock a mvc request for testing end to end my controller in spring.

The post request needs a request body but I get an error 400 telling me that required request body is missing even though I see its body using MockMvcResultsHandler print.

project architecture :

So here's my application.properties

spring.datasource.url=jdbc:h2:mem:tesdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=*****
spring.datasource.password=*****
spring.jpa.show-sql = true

Here's my test

@SpringBootTest
@AutoConfigureMockMvc
public class IntegrationTest {
    protected User mockUser;
  
    protected List<User> allUsers;

    @Autowired
    private MockMvc mvc;

    @Autowired
    private WebApplicationContext webApplicationContext;

    @BeforeEach
    public void setUp() {
        this.mvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build();
    }
    
    @Test
    void testGetAllUsers() throws Exception {
        this.mvc.perform(post("/api/users")
        .accept(MediaType.APPLICATION_JSON)
        .contentType(MediaType.APPLICATION_JSON)
        .characterEncoding("utf-8")     
        .content("{\"name\":\"name\"}"))
        .andDo(print())
        .andExpect(status().isCreated());
   }
}

My @RestController

    @PostMapping(path = "/users")
    public @ResponseBody ResponseEntity<User> addNewUser(
        @RequestBody String name        
    ) {
        return userService.createUser(name);
    }

and my user @Service

public ResponseEntity<User> createUser(String name) {
        User user = new User();
        user.setName(name);
        userRepository.save(user);

And when I try to launch my test I get in my debug console

DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public org.springframework.http.ResponseEntity<java.lang.String> ....addNewType(java.lang.String,java.lang.Boolean)]

MockHttpServletRequest:
      HTTP Method = POST
      Request URI = /api/users
       Parameters = {}
          Headers = [Content-Type:"application/json;charset=utf-8", Accept:"application/json", Content-Length:"32"]
             Body = {"name":"concat"}
    Session Attrs = {}

and response is :

MockHttpServletResponse:
           Status = 400
    Error message = null
          Headers = []
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

get methods seems to work when I use the same architecture, body seems to be present in the console but servelt doesn't seem to see/understand the request body.

Upvotes: 0

Views: 5496

Answers (4)

MedMahmoud
MedMahmoud

Reputation: 165

Try to add double quotes (") on the string you are sending in content:

mvc.perform(post("/url")
                        .content("\"myName\"")
                        .contentType(MediaType.APPLICATION_JSON)
                        .accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk());

Because you need to send a simple String that's the argument:

public @ResponseBody ResponseEntity<User> addNewUser(
        @RequestBody String name){
....
}

If you need to send:

.content("{\"name\":\"name\"}"))

Then you would need a dto (for example UserDto with a property "name") as an argument of addNewUser method.

Upvotes: -1

eln
eln

Reputation: 93

So this was a simplified example of my real web service. Problem came from the fact that I used several time @RequestBody in the same request

public @ResponseBody ResponseEntity<User> addNewUser(
        @RequestBody String name ,
        @RequestBody String lastName,

which was the source of the problem.

To solve that I created a DTO like

public @ResponseBody ResponseEntity<User> addNewUser(
        @RequestBody UserDTO userDto

And now it is working fine

Upvotes: 1

vikash pandey
vikash pandey

Reputation: 9

Try Creating a explicit json and then pass in body, also in your controller, you are expecting a single string name, try getting that from the json. eg:

@Test
void testGetAllUsers() throws Exception {
    JSONObject json = new JSONObject();
    json.put("name", "john");
    this.mvc.perform(post("/api/users")
    .accept(MediaType.APPLICATION_JSON)
    .contentType(MediaType.APPLICATION_JSON)
    .characterEncoding("utf-8")     
    .content(json.toString())
    .andDo(print())
    .andExpect(status().isCreated()); }

And in your controller you can try something like this

@PostMapping(path = "/users")
public @ResponseBody ResponseEntity<User> addNewUser(
    @RequestBody String name        
) {
    JSONObject json = new JSONObject(name);
    String userName = json.getString("name");
    return userService.createUser(userName);
}

Upvotes: -1

Minesh
Minesh

Reputation: 166

Good Day!

Need to check:

  • API URL
  • Need to run spring application so test method able to call API URL.

Upvotes: -1

Related Questions