簡體   English   中英

如何在 Spring Boot 中為控制器編寫單元測試

[英]How to write unit test for controller in spring boot

我是單元測試和 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;
    }
}

響應DTO

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]

我在這里做錯了什么? 任何幫助將不勝感激。

你的測試可能是這樣的:

 @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. 請求映射

@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. 模擬依賴

除此之外,在您的測試中,您已使用@InjectMocksMyController進行了注釋,但您尚未@InjectMocksMyService' dependency. That will set the MyService' dependency. That will set the field of your controller to MyService' dependency. That will set the myService field of your controller to MyService' dependency. That will set the field of your controller to null . To fix that you need to mock . 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);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM