java - Spring 启动: MockMvc returning strange responses

标签 java spring rest spring-boot mockmvc

我有以下 Controller :

RestApiController.java

package com.spring.ocr.rest.restconsume.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.UriComponentsBuilder;

import com.spring.ocr.rest.restconsume.model.User;
import com.spring.ocr.rest.restconsume.service.UserService;
import com.spring.ocr.rest.restconsume.util.CustomErrorType;

@RestController
@RequestMapping("/api")
public class RestApiController {

    @Autowired
    UserService userService;

    @RequestMapping(method = RequestMethod.GET, value = "/user/")
    public ResponseEntity<List<User>> listAllUsers() {
        final List<User> users = userService.findAllUsers();
        if(users.isEmpty()) {
            return new ResponseEntity<>(HttpStatus.NO_CONTENT);
        }
        return new ResponseEntity<List<User>>(users, HttpStatus.OK);
    }

    @RequestMapping(method = RequestMethod.GET, value = "/user/{id}")
    public ResponseEntity<?> getUser(@PathVariable("id") long id) {
        final User user = userService.findUserById(id);
        if(user == null) {
            return new ResponseEntity<>(new CustomErrorType(String.format("User with id %s not found", id)), HttpStatus.NOT_FOUND);
        }
        return new ResponseEntity<User>(user, HttpStatus.OK);
    }

    @RequestMapping(method = RequestMethod.POST, value = "/user/")
    public ResponseEntity<?> createUser(@RequestBody User user, UriComponentsBuilder ucBuilder) {
        if(userService.doesUserExist(user)) {
            return new ResponseEntity<>(new CustomErrorType(String.format("Unable to create, user %s already exists", user.getName())), HttpStatus.CONFLICT);
        }
        userService.createUser(user);

        final HttpHeaders headers = new HttpHeaders();
        headers.setLocation(ucBuilder.path("/api/user/{id}").buildAndExpand(user.getId()).toUri());
        return new ResponseEntity<String>(headers, HttpStatus.CREATED);
    }

    @RequestMapping(method = RequestMethod.PUT, value = "/user/{id}")
    public ResponseEntity<?> updateUser(@PathVariable("id") long id,@RequestBody User user) {
        User currentUser = userService.findUserById(id);
        if(currentUser == null) {
            return new ResponseEntity<>(new CustomErrorType(String.format("Unable to create update, User with id %s not found", user.getId())), HttpStatus.NOT_FOUND);
        }
        currentUser.setName(user.getName());
        currentUser.setAge(user.getAge());
        currentUser.setSalary(user.getSalary());

        userService.updateUser(currentUser);
        return new ResponseEntity<User>(currentUser, HttpStatus.OK);
    }

    @RequestMapping(method = RequestMethod.DELETE, value = "/user/{id}")
    public ResponseEntity<?> deleteUser(@PathVariable("id") long id) {
        User user = userService.findUserById(id);

        if(user == null) {
            return new ResponseEntity<>(new CustomErrorType(String.format("Unable to delete user, user with id %s not found", id)), HttpStatus.NOT_FOUND);
        }
        userService.deleteUserById(id);
        return new ResponseEntity<User>(HttpStatus.NO_CONTENT);
    }

    @RequestMapping(method = RequestMethod.DELETE, value = "/user/")
    public ResponseEntity<User> deleteAllUsers() {
        userService.deleteAllUsers();
        return new ResponseEntity<User>(HttpStatus.NO_CONTENT);
    }
 }

我已经使用mockMvc 设置了 Web 层的测试,并按照标准模拟了用户服务 bean:

RestApiControllerUnitTest.java

package com.spring.ocr.rest.restconsume.controller;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import java.util.ArrayList;
import java.util.List;

import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.spring.ocr.rest.restconsume.model.User;
import com.spring.ocr.rest.restconsume.service.UserService;

@RunWith(SpringRunner.class)
@WebMvcTest(RestApiController.class)
public class RestApiControllerUnitTest {

    @Autowired
    private MockMvc mockMvc;
    @MockBean
    UserService userService;
    @Autowired
    ObjectMapper objectMapper;

    private final List<User> dummyUserList = getDummyUserList();
    private final User dummyUser = new User((long)1, "Dave", (short)30, (double)30000);
    private final User dummyUpdatedUser = new User((long)1, "David", (short)31, (double)35000);

    @Test
    public void test_listAllUsers_userListSizeIs4_returnsListSizeOf4AndOkStatus() throws Exception {
        when(userService.findAllUsers()).thenReturn(dummyUserList);
        this.mockMvc.perform(get("/api/user/"))
            .andDo(print())
            .andExpect(status().isOk())
            .andExpect(jsonPath("$", hasSize(4)));
    }

    @Test
    public void test_listAllUsers_userListIsEmpty_returnsNoContentStatus() throws Exception {
        when(userService.findAllUsers()).thenReturn(new ArrayList<User>());
        this.mockMvc.perform(get("/api/user/"))
            .andDo(print())
            .andExpect(status().isNoContent());
    }

    @Test
    public void test_getUser_userExists_returnsUser() throws Exception {
        when(userService.findUserById(dummyUser.getId())).thenReturn(dummyUser);
        this.mockMvc.perform(get("/api/user/" + dummyUser.getId()))
            .andDo(print())
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.id",is((int)dummyUser.getId())))
            .andExpect(jsonPath("$.name", is(dummyUser.getName())))
            .andExpect(jsonPath("$.age", is((int)dummyUser.getAge())))
            .andExpect(jsonPath("$.salary", is(dummyUser.getSalary())));
    }

    @Test
    public void test_getUser_userDoesntExist_returnsNotFoundStatusAndCustomErrorString() throws Exception {
        when(userService.findUserById(dummyUser.getId())).thenReturn(null);
        this.mockMvc.perform(get("/api/user/"+dummyUser.getId()))
            .andDo(print())
            .andExpect(status().isNotFound())
            .andExpect(content().string(containsString("User with id 1 not found")));
    }

    @Test
    public void test_createUser_userDoesNotExist_userCreated() throws Exception {
        final String dummyUserJson = objectMapper.writeValueAsString(dummyUser);
        when(userService.doesUserExist(dummyUser)).thenReturn(false);
        MvcResult result = this.mockMvc.perform(post("/api/user/")
            .contentType(MediaType.APPLICATION_JSON)
            .content(dummyUserJson))
            .andDo(print())
            .andExpect(status().isCreated())
            .andReturn();
        final String header = result.getResponse().getHeader("Location");
        assertThat(header, is("http://localhost/api/user/1"));
    }

    @Test
    public void test_createUser_userExists_returnsNotFoundStatusAndCustomErrorMessage() throws Exception {
        final String dummyUserJson = objectMapper.writeValueAsString(dummyUser);
        final String expectedContent = String.format("Unable to create, user %s already exists", dummyUser.getName());
        when(userService.doesUserExist(anyObject())).thenReturn(true);
        this.mockMvc.perform(post("/api/user/")
            .contentType(MediaType.APPLICATION_JSON)
            .content(dummyUserJson))
            .andDo(print())
            .andExpect(status().isConflict())
            .andExpect(jsonPath("$.errorMessage", is(expectedContent)));
    }

    @Test
    public void test_updateUser_userExists_returnsOkStatusAndUpdatedUser() throws Exception {
        final String dummyUpdatedUserJson = objectMapper.writeValueAsString(dummyUpdatedUser);
        when(userService.findUserById(dummyUser.getId())).thenReturn(dummyUser);
        doNothing().when(userService).updateUser(dummyUser);
        this.mockMvc.perform(put("api/user/" + dummyUser.getId())
            .contentType(MediaType.APPLICATION_JSON)
            .content(dummyUpdatedUserJson))
            .andDo(print())
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.age", is(dummyUpdatedUser.getAge())))
            .andExpect(jsonPath("$.name", is(dummyUpdatedUser.getName())))
            .andExpect(jsonPath("$.salary", is(dummyUpdatedUser.getSalary())));
    }

    @Test
    public void test_deleteUser_userExists_returnNoContentStatus() throws Exception {
        when(userService.findUserById(dummyUser.getId())).thenReturn(dummyUser);
        this.mockMvc.perform(delete("api/user/" + dummyUser.getId()))
            .andDo(print())
            .andExpect(status().isNotFound());
    }

    @Test
    public void test_deleteUser_userDoesntExist_returnsNotFoundStatusAndCustomErrorMessage () throws Exception {
        when(userService.findUserById(dummyUser.getId())).thenReturn(null);
        final String expectedContent = String.format("Unable to create update, User with id %s not found", dummyUser.getName());
        this.mockMvc.perform(delete("api/user/"+dummyUser.getId()))
            .andDo(print())
            .andExpect(status().isNotFound())
            .andExpect(jsonPath("$.errorMessage", is(expectedContent)));
    }

    @Test
    public void test_deleteAllUsers_usersListPopulated_returnNoContentStatus() throws Exception {
        this.mockMvc.perform(delete("api/user/").contentType(MediaType.APPLICATION_JSON))
            .andDo(print())
            .andExpect(status().isNotFound());
    }

    private List<User> getDummyUserList() {
        final List<User> dummyUserList = new ArrayList<>();
        dummyUserList.add(new User((long)1, "Dave", (short)30, (double)30000));
        dummyUserList.add(new User((long)2, "Jess", (short)20, (double)20000));
        dummyUserList.add(new User((long)3, "Mike", (short)40, (double)40000));
        dummyUserList.add(new User((long)4, "Molly", (short)50, (double)50000));
        return dummyUserList;
    }
}

测试 test_updateUser_userExists_returnsOkStatusAndUpdatedUser 返回 404 而不是 200 状态,并且 test_deleteUser_userDoesntExist_returnsNotFoundStatusAndCustomErrorMessage 未返回正文中的错误消息,这暗示 404 不是“真正的”404(它没有返回,因为正确的响应正在返回,它由于其他原因而返回)。我还认为其他一些 404 状态可能会在相同的上下文下返回。

最佳答案

问题是由于失败测试中使用的 Controller 方法上缺少“/”造成的。

关于java - Spring 启动: MockMvc returning strange responses,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46349281/

相关文章:

java - 在一个类字段中处理一个 Spring bean/接口(interface)的多个实现

java - 从Android Studio中的 fragment 调用方法时如何避免空指针异常?

java - Spring Boot 应用程序在外部 TOMCAT 中启动后立即关闭

java - 在 jersey 2.x 中使用 GET 将查询参数列表发送到 jersey 客户端?

java - 如何从 Spring Boot Restful GET 调用返回对象属性的子集?

java - Observable-订阅两种方法

java - MAC OS AppleScript - 静默安装 Java?

java - Spring MVC htmlspecialchars() 替代方案

java - 在最大消息长度 : 2048 with payload-deserializing-transformer 之前未找到 CRLF

java - Hibernate- 无法延迟初始化角色集合 : beans. Language.patients,无法初始化代理 - 无 session