我是单元测试和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]
我在这里做错了什么?任何帮助将不胜感激。
答案 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)
您的测试存在一些问题:
@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;
}
}
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)));
}
除此之外,在测试中,您用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)));
}
}
MyService
不满足测试条件一切正常时,您的控制器将响应:
ResponseEntity<ResponseDTO> finalEntity = ResponseEntity.ok().body(finalResponse);
,它将返回状态码200。因此,您要么必须修改测试以期望:
.andExpect(status().isOk())
或者您应该更新控制器以返回201状态代码:
ResponseEntity<ResponseDTO> finalEntity = ResponseEntity.created(null).body(finalResponse);