Search code examples
javaspring-bootjunitmockmvc

Junit MockMvc perform POST with path variable in URL return 404 not found


I have a SpringBoot application with this method in the controller to create an user in the database. The controller is working fine in Postman.

@RestController
@RequestMapping("/v1")
public class UserController {

  @PostMapping(value = "/user/{id}")
  public void createUser(@PathVariable Integer id, @Valid @RequestBody User request,
        BindingResult bindingResult) throws Exception {

    if (bindingResult.hasErrors()) {        
        throw new RequestValidationException(VALIDATION_ERRORS, bindingResult.getFieldErrors());
    }               
    userService.createUser(id, request), HttpStatus.CREATED);
}

Now I have a junit test case to test this method and I am getting a 404

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyApp.class)
public class UserTest {

  private MockMvc mockMvc;
  final String CREATE_USER_URL = "/v1/user/" + "10";

  private final MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(),
        MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8"));

@Test
public void testCreateUser() throws Exception { 

  mockMvc.perform(post(CREATE_USER_URL)  
   // doesn't work either if I put "/v1/user/10" or post("/v1/user/{id}", 10) here
            .content(TestUtils.toJson(request, false))
            .contentType(contentType))
            .andDo(print())
            .andExpect(status().isCreated())
            .andReturn();  
 }

But in the log, I was able to see the correct url:

MockHttpServletRequest:

  HTTP Method = POST
  Request URI = /v1/user/10
  Parameters = {}

Can someone please let me know why I am getting a 404 NOT Found? Thanks.


Solution

  • From docs you need @AutoConfigureMockMvc on class and @Autowire MockMvc

    Another useful approach is to not start the server at all, but test only the layer below that, where Spring handles the incoming HTTP request and hands it off to your controller. That way, almost the full stack is used, and your code will be called exactly the same way as if it was processing a real HTTP request, but without the cost of starting the server. To do that we will use Spring’s MockMvc, and we can ask for that to be injected for us by using the @AutoConfigureMockMvc annotation on the test case:

    Code :

    @RunWith(SpringRunner.class)
    @SpringBootTest
    @AutoConfigureMockMvc
    public class UserTest {
    
       @Autowire
       private MockMvc mockMvc;
       final String CREATE_USER_URL = "/v1/user/" + "10";
    
       private final MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(),
        MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8"));
    
      @Test
      public void testCreateUser() throws Exception { 
    
        mockMvc.perform(post(CREATE_USER_URL)  
     // doesn't work either if I put "/v1/user/10" or post("/v1/user/{id}", 10) here
            .content(TestUtils.toJson(request, false))
            .contentType(contentType))
            .andDo(print())
            .andExpect(status().isCreated())
            .andReturn();  
       }
    }