MockMVC in junit tests - checking result for List<Object> and Map<Enum, Object>

19,906

The jsonPath helpers are very useful for asserting your responses are valid from the perspective of the consumers of your API; these consumers receive a JSON repsonse so it makes sense to perform your assertions on that JSON.

The following assertions will work for the payload from /consumers/1/persons

.andExpect(jsonPath("$[0].firstName", is("Ligza")))
.andExpect(jsonPath("$[1].firstName", is("Vekrir")))

So, the array is 0-based and you access entries in each element by the (case sensitive) name.

However, if you really want to assert against the original types (e.g. PersonDto) then you can read the entire JSON string and use a JSON mapper (such as Jackson or Gson) to deserialize it back into its original class representation. For example:

MvcResult result = mockMvc.perform(get(getUri("/consumers/1/persons")))
        .andExpect(status().isOk())
        .andReturn();

ObjectMapper mapper = new ObjectMapper();

// this uses a TypeReference to inform Jackson about the Lists's generic type
List<PersonDto> actual = mapper.readValue(result.getResponse().getContentAsString(), new TypeReference<List<PersonDto>>() {});

// now just assert equality (or whatever) against the actual PersonDto
Share:
19,906
xross
Author by

xross

"I destroyed my body for a peace of mind I've never got."

Updated on June 08, 2022

Comments

  • xross
    xross almost 2 years

    I have problems with mockMVC and test written with that. My tests fails. I have two tests methods:

    @Test
    public void getPersonsForApiConsumerTest() throws Exception {
        mockMvc.perform(get(getUri("/consumers/1/persons")))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$", hasSize(2)))
                .andExpect(jsonPath("$[1].name", is("Ligza")))
                .andExpect(jsonPath("$[2].name", is("Vekrir")));
    
    }
    
    @Test
    public void getPersonsForApiConsumerMapTest() throws Exception {
        mockMvc.perform(get(getUri("/consumers/1/persons/map")))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$[1].name", is("Verkir")))
                .andExpect(jsonPath("$[2].name", is("Ligza")));
    }
    

    Rest methods with mapping:

     @RequestMapping(value = "/{consumerId}/persons")
        public List<PersonDto> getPersonsForApiConsumer(@PathVariable("consumerId") Integer consumerId) throws IOException {
            return apiConsumerService.getPersonsListForApiConsumer(consumerId);
        }
    
        @RequestMapping(value = "/{consumerId}/persons/map")
        public Map<ApiConsumerPersonRole, List<Person>> getPersonsForApiConsumerMap(@PathVariable("consumerId") Integer consumerId) throws IOException {
            return apiConsumerService.getPersonsMapForApiConsumer(consumerId);
        }
    

    By Postman I can gain data such:

    for list:

    [
        {
            "id": 1,
            "firstName": "Ligza",
            "lastName": "Zetasor",
            "role": "REPRESENTATIVE",
            "phone": "123123123",
            "email": "[email protected]"
        },
        {
            "id": 4,
            "firstName": "Vekrir",
            "lastName": "Omegaram",
            "role": "SECURITY_OFFICER",
            "phone": "354654545",
            "email": "[email protected]"
        }
    ]
    

    for map:

    {
        "SECURITY_OFFICER": [
            {
                "id": 4,
                "firstName": "Vekrir",
                "lastName": "Omegaram",
                "telephone": "354654545",
                "email": "[email protected]"
            }
        ],
        "REPRESENTATIVE": [
            {
                "id": 1,
                "firstName": "Ligza",
                "lastName": "Zetasor",
                "telephone": "123123123",
                "email": "[email protected]"
            }
        ],
        "COMPLAINT_OFFICER": [],
        "LOCAL_REPRESENTATIVE": []
    }
    

    I dont have any clue how to write it properly. I want to check the data inside this list and map.

    Is it possible to stream it into that collection or check it easily in the way it is wriiten already?


    Edit: logs:

    java.lang.AssertionError: No value at JSON path "$[1].firstname", exception: No results for path: $[1]['firstname']
    
        at org.springframework.test.util.JsonPathExpectationsHelper.evaluateJsonPath(JsonPathExpectationsHelper.java:245)
        at org.springframework.test.util.JsonPathExpectationsHelper.assertValue(JsonPathExpectationsHelper.java:73)
        at org.springframework.test.web.servlet.result.JsonPathResultMatchers$1.match(JsonPathResultMatchers.java:87)
        at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:171)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
        at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
        at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
        at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
        at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
        at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
        at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
        at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
        at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
        at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
        at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
    
    
    Process finished with exit code -1
    
    MockHttpServletResponse:
               Status = 200
        Error message = null
              Headers = {X-Content-Type-Options=[nosniff], X-XSS-Protection=[1; mode=block], Cache-Control=[no-cache, no-store, max-age=0, must-revalidate], Pragma=[no-cache], Expires=[0], X-Frame-Options=[DENY], Content-Type=[application/json;charset=UTF-8]}
         Content type = application/json;charset=UTF-8
                 Body = {"COMPLAINT_OFFICER":[],"REPRESENTATIVE":[{"id":1,"firstName":"Ligza","lastName":"Zetasor","telephone":"123123123","email":"[email protected]"}],"LOCAL_REPRESENTATIVE":[],"SECURITY_OFFICER":[{"id":4,"firstName":"Vekrir","lastName":"Omegaram","telephone":"354654545","email":"[email protected]"}]}
        Forwarded URL = null
       Redirected URL = null
              Cookies = []
    
    java.lang.AssertionError: No value at JSON path "$[1].firstname", exception: Filter: [1]['firstname'] can only be applied to arrays. Current context is: {COMPLAINT_OFFICER=[], REPRESENTATIVE=[{"id":1,"firstName":"Ligza","lastName":"Zetasor","telephone":"123123123","email":"[email protected]"}], LOCAL_REPRESENTATIVE=[], SECURITY_OFFICER=[{"id":4,"firstName":"Vekrir","lastName":"Omegaram","telephone":"354654545","email":"[email protected]"}]}
    
        at org.springframework.test.util.JsonPathExpectationsHelper.evaluateJsonPath(JsonPathExpectationsHelper.java:245)
        at org.springframework.test.util.JsonPathExpectationsHelper.assertValue(JsonPathExpectationsHelper.java:73)
        at org.springframework.test.web.servlet.result.JsonPathResultMatchers$1.match(JsonPathResultMatchers.java:87)
        at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:171)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
        at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
        at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
        at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
        at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
        at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
        at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
        at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
        at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
        at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
        at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)