[英]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);
}
}
希望能幫助到你!
你的測試有幾個問題:
@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;
}
}
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)));
}
除此之外,在您的測試中,您已使用@InjectMocks
對MyController
進行了注釋,但您尚未@InjectMocks
其MyService' 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)));
}
}
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.