Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.4k views
in Technique[技术] by (71.8m points)

java - How to use correctly MockMvc to test post method in Junit?

I am unit testing with MockMvc for the first time and I have not figured it out yet how to use it correctly. I am trying to test a simple POST method. My code (class code) works good, I tested it with postman, so clearly the problem is with the testing code.

Controller:

@Controller
@RequestMapping("/employees")
public class EmployeeController {

    private final EmployeeService employeeService;
    private final EmployeeModelAssembler assembler;

    @Autowired
    public EmployeeController(EmployeeService employeeService, EmployeeModelAssembler assembler){
        this.employeeService = employeeService;
        this.assembler = assembler;
    }

    @PostMapping()
    public ResponseEntity<?> addEmployee(@RequestBody Employee employee, UriComponentsBuilder builder){
        EntityModel<Employee> entityModel = this.assembler.toModel(this.employeeService.addEmployee(employee));
        return ResponseEntity.created(entityModel.getRequiredLink(IanaLinkRelations.SELF).toUri()).body(entityModel);
    }
...

There are more methods above, but addEmployee is the method i am trying to test.

Test:

@ExtendWith(SpringExtension.class)
@WebMvcTest(EmployeeController.class)
@AutoConfigureMockMvc
public class EmployeeControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private EmployeeService employeeService;

    @MockBean
    private EmployeeModelAssembler assembler;

    @InjectMocks
    private EmployeeController employeeController;

    @Before
    public void setUp(){
        MockitoAnnotations.openMocks(this);
    }


    @Test
    public void testAddEmployee() throws Exception {
        String mockEmployeeJson =
                "    "firstName": "new",
" +
                "    "lastName": "Employee",
" +
                "    "emailAddress": "[email protected]",
" +
                "    "roll": "Software Engineer",
" +
                "    "team": 
" +
                "    {
" +
                "        "teamId": 1
" +
                "    }
" +
                "}";

        mockMvc.perform(MockMvcRequestBuilders.post("/employees")
                .contentType(MediaType.APPLICATION_JSON)
                .content(mockEmployeeJson)
                .accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk());
    }

output:


MockHttpServletRequest:
      HTTP Method = POST
      Request URI = /employees
       Parameters = {}
          Headers = [Content-Type:"application/json;charset=UTF-8", Accept:"application/json", Content-Length:"171"]
             Body =     "firstName": "new",
    "lastName": "Employee",
    "emailAddress": "[email protected]",
    "roll": "Software Engineer",
    "team": 
    {
        "teamId": 1
    }
}
    Session Attrs = {}

Handler:
             Type = com.Ventura.Notifier.controller.EmployeeController
           Method = com.Ventura.Notifier.controller.EmployeeController#addEmployee(Employee, UriComponentsBuilder)

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = org.springframework.http.converter.HttpMessageNotReadableException

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

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 400
    Error message = null
          Headers = []
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

java.lang.AssertionError: Status expected:<200> but was:<400>
Expected :200
Actual   :400
<Click to see difference>

Edit 1 changed the test to:

    private Employee employee;

    @BeforeEach
    public void setUpEmployee(){
        Team team = new Team();
        team.setTeamId(1);

        employee = new Employee();
        employee.setTeam(team);
        employee.setRoll("software developer");
        employee.setLastName("Levi");
        employee.setEmailAddress("[email protected]");
        employee.setFirstName("David");
    }


    @Test
    public void testAddEmployee() throws Exception {
        ObjectMapper objectMapper = new ObjectMapper();

        mockMvc.perform(MockMvcRequestBuilders.post("/employees")
                .contentType(MediaType.APPLICATION_JSON)
                .content(objectMapper.writeValueAsString(employee))
                .accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk());
    }

but I am getting a null pointer exception.

Edit 2

I solved the null pointer exception, not sure why though. if anyone is interested in the solution:

The test:

@Test
public void testAddEmployee() throws Exception {

    ObjectMapper objectMapper = new ObjectMapper();

    mockMvc.perform(MockMvcRequestBuilders.post("/employees")
            .contentType(MediaType.APPLICATION_JSON)
            .content(objectMapper.writeValueAsString(employee))
            .accept(MediaType.APPLICATION_JSON))
            .andExpect(status().is2xxSuccessful());
}

and i changed the return statement in the addEmployee method to:

    return new ResponseEntity<>(entityModel, HttpStatus.CREATED);
question from:https://stackoverflow.com/questions/65939134/how-to-use-correctly-mockmvc-to-test-post-method-in-junit

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your JSON formated input request body is incorrectly formatted, I will recommend using Map with objectMapper, Map.of is from jdk-9 if you are using lower version you can replacse it by creating another map using new keyword

@Test
public void testAddEmployee() throws Exception {

   Map<String,Object> body = new HashMap<>();
    body.put("firstName","new");
    body.put("lastName","Employee");
    body.put("emailAddress","[email protected]");
    body.put("roll","Software Engineer");
    body.put("team",Map.of("teamId",1));
      

    mockMvc.perform(MockMvcRequestBuilders.post("/employees")
            .contentType(MediaType.APPLICATION_JSON)
            .content(objectMapper.writeAsString(body))
            .accept(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk());
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...