Hot questions for Using Mockito in 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.
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>
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.
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.
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.