Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Content type not set" when Unit Testing Spring RESTful controller

I have a Rest controller similar to this one:

@RestController
public class UserRestController {

    @Autowired
    private UserService userService;

    @RequestMapping(value = "/user/activate", method = RequestMethod.POST)
    public ResponseEntity<UserDTO> activate(
            @RequestParam(required = true) final String email,
            @RequestParam(required = true) final String key) {

        UserDTO userDTO = userService.activateAccount(email, key);
        return new ResponseEntity<UserDTO>(userDTO, HttpStatus.OK);
    }
}

When I invoke it using Postman and I don't send the 'key' parameter, I receive this JSON message:

{
    "timestamp": 1446211575193,
    "status": 400,
    "error": "Bad Request",
    "exception": "org.springframework.web.bind.MissingServletRequestParameterException",
    "message": "Required String parameter 'key' is not present",
    "path": "/user/activate"
}

On the other hand, I am testing this method with JUnit and the MockMVC Spring utility.

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = ApplicationConfig.class)
@WebAppConfiguration
public class UserRestControllerTest {

    private static MockMvc mockMvc;

    @Mock
    private UserService userService;

    @InjectMocks
    private UserRestController userRestController;

    @Before
    public void setup() {

        MockitoAnnotations.initMocks(this);
        mockMvc = MockMvcBuilders
                .standaloneSetup(userRestController)
                .setMessageConverters(
                        new MappingJackson2HttpMessageConverter(),
                        new Jaxb2RootElementHttpMessageConverter()).build();

    }

    @Test
    public void testActivateRequiredParams() throws Exception {

        mockMvc.perform(
                MockMvcRequestBuilders.post("/user/activate")
                .contentType(MediaType.APPLICATION_FORM_URLENCODED)
                .accept(MediaType.APPLICATION_JSON))
                .andDo(MockMvcResultHandlers.print())
                .andExpect(MockMvcResultMatchers.status().isBadRequest())
                .andExpect(
                        MockMvcResultMatchers.content().contentType(
                                UtilsUnitTest.APPLICATION_JSON_UTF8))
                .andExpect(
                        jsonPath(
                                "message",
                                is("Required String parameter 'email' is not present")));

     }
}

But when I execute this test I notice that the response is not a JSON message. In fact, I get an exception:

java.lang.AssertionError: Content type not set

Particularly, the completed result is

MockHttpServletRequest:
         HTTP Method = POST
         Request URI = /user/activate
          Parameters = {}
             Headers = {Content-Type=[application/x-www-form-urlencoded]}

             Handler:
                Type = com.company.controller.UserRestController
              Method = public org.springframework.http.ResponseEntity<com.company.dto.UserDTO> com.company.controller.UserRestController.activate(java.lang.String,java.lang.String)

               Async:
       Async started = false
        Async result = null

  Resolved Exception:
                Type = org.springframework.web.bind.MissingServletRequestParameterException

        ModelAndView:
           View name = null
                View = null
               Model = null

            FlashMap:

MockHttpServletResponse:
              Status = 400
       Error message = Required String parameter 'email' is not present
             Headers = {}
        Content type = null
                Body = 
       Forwarded URL = null
      Redirected URL = null
             Cookies = []

I deduce that when an exception is thrown this is not converted to JSON format (I get a correct JSON result when I send the email and key parameters)

The question is obvious: what should I change in the Unit Test configuration to get a JSON error message in case of an exception be thrown?

like image 539
Sobrino Avatar asked Oct 30 '15 13:10

Sobrino


People also ask

How do you write a unit test for rest controller?

Writing a Unit Test for REST Controller First, we need to create Abstract class file used to create web application context by using MockMvc and define the mapToJson() and mapFromJson() methods to convert the Java object into JSON string and convert the JSON string into Java object.

Is Springboottest a unit test?

No. A unit test is to test a single component in isolation. Using constructor injection in your beans allows you to very simply call new SomeService(myMock) , no Spring required.


Video Answer


1 Answers

The problem is that the test stops after following assertion fails:

.andExpect(MockMvcResultMatchers.content().contentType(UtilsUnitTest.APPLICATION_JSON_UTF8))

Beside this, jsonPath("message"... won't hit anything. To validate the returned error message use MockMvcResultMatchers.status().reason(<ResultMatcher>).

The following test should do the job:

@Test
public void testActivateRequiredParams() throws Exception {
    final ResultActions result = mockMvc
            .perform(MockMvcRequestBuilders.post("/user/activate")
                    .contentType(MediaType.APPLICATION_FORM_URLENCODED).accept(MediaType.APPLICATION_JSON))
            .andDo(MockMvcResultHandlers.print());
    result.andExpect(MockMvcResultMatchers.status().isBadRequest());
    result.andExpect(MockMvcResultMatchers.status().reason(is("Required String parameter 'email' is not present")));
}

But think about if this (testing for error messages) is a good idea in general, maybe see this discussion.

like image 137
Kevin Peters Avatar answered Sep 20 '22 15:09

Kevin Peters