如何在春季启动中编写控制器的单元测试

时间:2019-05-10 03:14:10

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

我是单元测试和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]

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

2 个答案:

答案 0 :(得分:2)

您的测试可能是这样的:

 @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);
    }

}

希望有帮助!

答案 1 :(得分:2)

您的测试存在一些问题:

1。请求映射

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

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

@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。模拟依赖项

除此之外,在测试中,您用MyController注释了@InjectMocks,但没有嘲笑其MyService' dependency. That will set the myService field of your controller to. To fix that you need to mock MyService'也是:

@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);