【问题标题】:How to write unit test for controller in spring boot如何在 Spring Boot 中为控制器编写单元测试
【发布时间】:2019-09-27 22:14:13
【问题描述】:

我是单元测试和 TDD 的新手。我想为我在 Spring Boot 中编写的控制器和服务类应用单元测试。

我已经使用教程实现了测试类。但是,我无法成功实施。我已经包含了我当前的代码。

控制器

@RestController
@RequestMapping("/api")
public class MyController {
    private static final Logger LOGGER = LoggerFactory.getLogger(AdminController.class);
    @Autowired
    MyService myService;

    @PostMapping("/create")
    public ResponseEntity<?> createUser(@RequestHeader("Authorization") String token, 
        @RequestBody User user){
        ResponseDTO finalResponse = new ResponseDTO();
        try {
            ResponseEntity<?> entity = myService.create(token, user);             
            finalResponse.setMessageCode(entity.getStatusCode());
            finalResponse.setMessage("Success");
            finalResponse.setError(false);
            ResponseEntity<ResponseDTO> finalEntity = ResponseEntity.ok().body(finalResponse);
        return finalEntity;
        } catch (Exception e) {      
            finalResponse.setMessageCode(HttpStatus.EXPECTATION_FAILED);
            finalResponse.setMessage(e.getMessage());
            finalResponse.setError(true);
            ResponseEntity<ResponseDTO> finalEntity = 
            ResponseEntity.ok().body(finalResponse);
            return finalEntity;
    }
}

ResponseDTO

public class ResponseDTO {
    private HttpStatus messageCode;
    private String message;
    private String messageDetail;
    private Object body;
    private boolean error;

    //setters and getters
}

当前测试类

@RunWith(SpringRunner.class)
public class MyControllerTest {
    private MockMvc mockMvc;

    @InjectMocks
    private MyController myController;

    @Before
    public void setUp() throws Exception {
    mockMvc = MockMvcBuilders.standaloneSetup(myController).build();
    }

    @Test
    public void testCreateUser() throws Exception {
        mockMvc.perform(post("/api/create")
            .accept(MediaType.APPLICATION_JSON))
            .andExpect(status().isCreated())
            .andExpect(jsonPath("$.*", Matchers.hasSize(1)));
    }

}

当我运行测试类时,我得到WARN Resolved [org.springframework.web.bind.MissingRequestHeaderException: Missing request header 'Authorization' for method parameter of type String]

我在这里做错了什么?任何帮助将不胜感激。

【问题讨论】:

  • 您错过了 .header("Authorization", "some value") 的 mockMvc。顺便说一句,.content("your testing payload") 也错过了。
  • 如果你正在为控制器编写测试,这不是单元测试。

标签: java rest unit-testing spring-boot junit


【解决方案1】:

你的测试可能是这样的:

 @Test
public void testCreateUser() throws Exception {
    mockMvc.perform(post("/api/create")
        .accept(MediaType.APPLICATION_JSON)
        .header("AUTH_TOKEN", TOKEN)
        .content(ObjectToJsonUtil.convertObjectToJsonBytes(user)))
        .andExpect(status().isCreated())
        .andExpect(jsonPath("$.*", Matchers.hasSize(1)));
}

您必须将对象用户转换为 json。 因此,您为此创建了一个 util 类:

public class ObjectToJsonUtil {
    public static byte[] convertObjectToJsonBytes(Object object)
            throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);

        JavaTimeModule module = new JavaTimeModule();
        mapper.registerModule(module);

        return mapper.writeValueAsBytes(object);
    }

}

希望对你有帮助!

【讨论】:

  • 感谢您的回答。如何使用模拟令牌?
  • 有一个 spring 注释可以模拟你的安全上下文。注释你的测试:@WithMockUser(username = "myUser", roles = { "myAuthority" })
  • 我在.content(user)) 中遇到错误,该错误表示 MockHttpServletRequestBuilder 类型中的方法内容(字节 [])不适用于参数(用户)
  • 我更新了我的答案。您必须使用 util 类将对象用户转换为 json。您如何处理服务中的授权令牌?只是为了检查是否需要验证。
【解决方案2】:

您的测试存在一些问题:

1。请求映射

@PostMapping("/create")
public ResponseEntity<?> createUser(
    @RequestHeader("Authorization") String token, 
    @RequestBody User user)

仅匹配具有名为 Authorization 的 HTTP 标头和可序列化为 User 的请求正文的 POST 请求。这些不是可选的。如果它们是可选的,您应该明确声明:

@PostMapping("/create")
public ResponseEntity<?> createUser(
   @RequestHeader(name = "Authorization", required = false) String token, 
   @RequestBody(required = false) User user) {

假设它们是必需的,您应该设置 MockMvc 以将两者都发送到您的控制器:

    @Test
    public void testCreateUser() throws Exception {
        mockMvc.perform(
                post("/api/create")
                  .header("Authorization", "XYZ")
                  .content("{\"firstName\": \"James\", \"lastName\": \"Gosling\"}")
                  .accept(MediaType.APPLICATION_JSON)
                )
               .andExpect(status().isCreated())
               .andExpect(jsonPath("$.*", Matchers.hasSize(1)));
    }

这里我假设你的 User 类是这样的:

public class User {

    private String firstName;

    private String lastName;

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
}

2。 Content-Type标头

此外,您应该为您的 MockMvc 请求设置内容类型标头,否则测试将失败并显示 415 - Unsupported Media Type。所以你的测试应该是这样的:

    @Test
    public void testCreateUser() throws Exception {
        mockMvc.perform(
                post("/api/create")
                  .header("Authorization", "XYZ")
                  .header("Content-Type", "application/json")
                  .content("{\"firstName\": \"James\", \"lastName\": \"Gosling\"}")
                  .accept(MediaType.APPLICATION_JSON)
                )
               .andExpect(status().isCreated())
               .andExpect(jsonPath("$.*", Matchers.hasSize(1)));
    }

3。模拟依赖项

除此之外,在您的测试中,您已经用@InjectMocks 注释了MyController,但您还没有嘲笑它的MyService' dependency. That will set themyServicefield of your controller tonull. To fix that you need to mockMyService':

@RunWith(SpringRunner.class)
public class MyControllerTest {

    private MockMvc mockMvc;

    // Mock
    @Mock
    private MyService myService;

    @InjectMocks
    private MyController myController;

    @Before
    public void setUp() throws Exception {
        mockMvc = MockMvcBuilders.standaloneSetup(myController).build();
    }

    @Test
    public void testCreateUser() throws Exception {
        // Configure mock myService
        when(myService.create(anyString(), any(User.class))).thenReturn(new ResponseEntity<>(HttpStatus.CREATED));

        mockMvc.perform(
                post("/api/create")
                  .header("Authorization", "XYZ")
                  .header("Content-Type", "application/json")
                  .content("{\"firstName\": \"James\", \"lastName\": \"Gosling\"}")
                  .accept(MediaType.APPLICATION_JSON)
                )
               .andExpect(status().isCreated())
               .andExpect(jsonPath("$.*", Matchers.hasSize(1)));
    }

}

4。 MyService不满足测试条件

当一切正常时,您的控制器会响应:

ResponseEntity<ResponseDTO> finalEntity = ResponseEntity.ok().body(finalResponse);

这将返回 200 的状态代码。所以您要么必须修改您的测试以期望:

.andExpect(status().isOk())

或者您应该更新您的控制器以返回 201 状态代码:

ResponseEntity<ResponseDTO> finalEntity = ResponseEntity.created(null).body(finalResponse);

【讨论】:

    猜你喜欢
    • 2019-11-05
    • 2019-11-19
    • 1970-01-01
    • 2015-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多