0

I am using MockMvc to test a controller. The controller has an ObjectMapper and HttpServletRequest as arguments. I instantiate the controller in my test class with these arguments. When I use MockMvc to make the request, the Name @RequestParam is successfully passed to the controller. However outside of this, the request is null. The accept header is set on the MockMvc request as:

mockMvc.perform(get("/birthday-cards?name=Jack").accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andDo(print());

when the request is accessed in the controller, the request header is null.

String accept = request.getHeader("Accept"); 

I believe this is because once I get into the controller method body, the request is using the MockHttpServletRequest created when initializing the Controller in the test class.

The full code of the controller:

@Controller
public class HappyBirthdayApiController implements HappyBirthdayApi {

    private final ObjectMapper objectMapper;

    private final HttpServletRequest request;

    @Autowired
    public HappyBirthdayController(ObjectMapper objectMapper, HttpServletRequest request) {
        this.objectMapper = objectMapper;
        this.request = request;
    }

    @Override
    public Optional<ObjectMapper> getObjectMapper() {
        return Optional.ofNullable(objectMapper);
    }

    @Override
    public Optional<HttpServletRequest> getRequest() {
        return Optional.ofNullable(request);
    }

    @Override
    public ResponseEntity<String> getHappyBirthday(@ApiParam(value = "Filter by name") @Valid @RequestParam(value = "name", required = false) String name) {
        //Request is null!
        String accept = request.getHeader("Accept");
        if (accept == null || !accept.equals(MediaType.APPLICATION_JSON_VALUE))
            throw new UnsupportedMediaTypeException("Accept header must be " + MediaType.APPLICATION_JSON_VALUE);
        );
        String message = "Happy Birthday " + name; 
        return new ResponseEntity<>(message, HttpStatus.OK);
    }
}

The test class:

public class BirthdayCardsApiControllerTest{
    private MockMvc mockMvc;
    private final MockHttpServletRequest mockHttpServletRequest = new MockHttpServletRequest();

    @InjectMocks
    private BirthdayCardsApiController controller;

    @Before
    public void setUp(){
        controller = new BirthdayCardsApiController(new ObjectMapper(), mockHttpServletRequest);
        MockitoAnnotations.initMocks(this);

        mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
    }

    @Test
    public void getHappyBirthdayTest() throws Exception{
        mockMvc.perform(get("/birthday-cards?name=Jack").accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andDo(print());
    }
}

Is there a way to share the same HttpServletRequest used by MockMvc and when instantiating the controller under test?

  • 1
    This seems like the wrong usage of `HttpServletRequest` to me. Your controller constructor should not take in the `HttpServletRequest`, instead it should be your API method `getHappyBirthday` that accepts it. – Tim Aug 18 '22 at 21:14
  • The classes were generated with swagger-codegen and that is how the classes were generated. Why do you think that is the wrong usage? – user2821694 Aug 19 '22 at 15:37
  • Did some digging, and not really a wrong usage of it [link to other post](https://stackoverflow.com/questions/49680692/spring-mvc-can-i-autowire-httpservletrequest-in-restcontroller). I suppose it's just a way I was not familiar with, the more you know. – Tim Aug 19 '22 at 16:37

0 Answers0