Hot questions for Using Mockito in spring test mvc

Top 10 Java Open Source / Mockito / spring test mvc

Question:

I have an api call as:

@RequestMapping(value = "/course", method = RequestMethod.GET)
ResponseEntity<Object> getCourse(HttpServletRequest request, HttpServletResponse response) throwsException {
        User user = userDao.getByUsername(request.getRemoteUser());

}

I'm getting the user null when I call this from the test class like:

HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
 Mockito.when(request.getRemoteUser()).thenReturn("test1");

    MvcResult result =  mockMvc.perform( get( "/course")
                    .contentType(MediaType.APPLICATION_JSON)
                    .andExpect( status().isOk() )
                    .andExpect( content().contentType( "application/json;charset=UTF-8" ) )
                    .andReturn();

When I debug request object I can see remoteUser=null. So how can I pass the value to remote user?


Answer:

You can use RequestPostProcessor in order to modify the MockHttpServletRequest in any fashion you want. In your case:

mockMvc.perform(get("/course").with(request -> {
                    request.setRemoteUser("USER");
                    return request;
                })...

And if you're stuck with older versions of Java:

mockMvc.perform(get("/course").with(new RequestPostProcessor() {
            @Override
            public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
                request.setRemoteUser("USER");
                return request;
            }
        })...

Question:

I have an application that uses Spring MVC for running a REST service (without Spring Boot). Context is mainly loaded from parents one. I have a controller and I would like to test it via MockMVC.

I have tried to set up local test context by hands, but it wasn't enough for running test. I assume, there should be extra beans I haven't set up.

My controller is:

@RestController
public class ProrertyEditorController extends AbstractPropertyEditorController {

    @Autowired
    protected PropertyEditorService prorertyEditorService;

    @RequestMapping(method = RequestMethod.DELETE, value = "/{dataType}/deletewithcontent")
@ResponseStatus(value = HttpStatus.OK)
public void deleteWithContent(@PathVariable("dataType") String dataType, @RequestParam("deleteall") boolean deleteAllContent, @RequestBody String node) {
    try {
        JSONArray itemsToDelete = new JSONArray(node);
        prorertyEditorService.deleteItemsWithContent(dataType, itemsToDelete, deleteAllContent);
    } catch (Exception e) {
        //handling exception
    }
}

Up to this moment, test for controller looks like this:

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("classpath*:configBeans1.xml")
public class ProrertyEditorControllerTest{
    private MockMvc mockMvc;

    @Mock
    private PropertyEditorService mockService;
    @InjectMocks
    private ProrertyEditorController controller;

    @Before
    public void setup() {
        mockMvc = MockMvcBuilders.standaloneSetup(new ProrertyEditorController()).build();
    }

    @Test
    public void deleteWithContentTest() throws Exception {
                   mockMvc.perform(delete("/full/path/{dataType}/deletewithcontent", type)
                .param("deleteall", "true")
                .param("node", "[{\"test key1\":\"test value1\"}, {\"test keys2\":\"test value2\"}]"));

        verify(mockService, times(1)).deleteItemsWithContent(eq("promotion"), eq(new JSONArray("[{\"test key1\":\"test value1\"}, {\"test keys2\": \"test value2\"}]")), eq(true));
    }

Unfortunately, it doesn't work due to

Failed to load ApplicationContext

and no bean is created

PS There is an option to use

MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();

However, it requires refactoring of controllers method, that is not possible


Answer:

It turned out that it is absolutely possible to do it. There are just a few configs required to launch it.

  1. You will need spring-test in your pom.xml to make it work

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <scope>test</scope>
    </dependency>
    
  2. Create a testContext.xml file. In my case, it was literally empty(!):

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    </beans>
    

Nevertheless, it is still required, otherwise, MockMVC will not start since there is no context.

  1. Config your controllerTest class with the following annotations:

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = "classpath*:testContextConfig.xml")
    @WebAppConfiguration
    public class ControllerTest {        ...    }
    

It should me mentioned that without @ContextConfiguration MockMVC won't work.

  1. Create a MockMVC instance in @Before method:

    private MockMvc mockMvc;
    
    @Mock
    private Service mockService;
    
    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        mockMvc = MockMvcBuilders.standaloneSetup(new Controller(mockService))
                .setHandlerExceptionResolvers(exceptionResolver()) //crutial for standaloneSetup of MockMVC
                .build();
    }
    

As far as I've understood, setHandlerExceptionResolvers is a crucial part of mockMVC setup.

Basically, that's it.