在 JUnit 5 中,为什么 postMethod 抛出 TransactionSystemException 而不是 return ResponseEntity with bad request?
In JUnit 5, why are postMethod throwing TransactionSystemException instead return ResponseEntity with bad request?
我是 Spring Boot 和 JUnit 的新手,所以我正在尝试构建一个具有如下验证约束的 Rest API:
实体class:
@Entity
public class CareerLevel {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer careerLevelId;
@NotNull
@NotEmpty
@Size(max = 50)
private String careerLevel;
// Getters and Setters
}
控制器:
@PostMapping
public ResponseEntity<CareerLevel> postCareerLevel(@RequestBody @Valid CareerLevel careerLevel) {
// saving data
CareerLevel body = careerLevelRepository.save(careerLevel);
return ResponseEntity.status(201).body(body);
}
当我使用无效值(空值、太长的字符串等)在 Insomnia(或任何其他 HTTP 客户端)上测试 post 方法时,它返回错误请求(正是我所期望的)。但是当我 运行 我的测试 class 时,它抛出了一个名为 TransactionSystemException
的异常
测试方法:
@Test
void testPostCareerLevelInvalidValues() {
CareerLevel careerLevel = new CareerLevel();
careerLevel.setCareerLevel("tooLongStriiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiing");
ResponseEntity<CareerLevel> response1 = controller.postCareerLevel(careerLevel); // throwing TransactionSystemException
assertEquals(400, response1.getStatusCode().value());
}
如何处理该异常并获取响应数据?
您好,我在本地尝试了您的代码并添加了一个 lombok 注释来为实体创建一个构建器。
see @Builder
我建议在测试您的控制器时使用 MockMvc
class。
我也用mockito模拟了CareerLevelRepository
注入到CareerLevelController
@ExtendWith(MockitoExtension.class)
class CareerLevelControllerTest {
@Mock
private CareerLevelRepository careerLevelRepository;
@InjectMocks
private CareerLevelController careerLevelController;
private MockMvc mockMvc;
@BeforeEach
void setUp() {
mockMvc = MockMvcBuilders.standaloneSetup(careerLevelController)
.build();
}
private final ObjectMapper objectMapper = new ObjectMapper();
@Test
void testPostCareerLevelInvalidValues() throws Exception {
CareerLevel request = CareerLevel.builder()
.careerLevel("tooLongStriiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiing")
.build();
this.mockMvc
.perform(post("/career-levels").contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(request)))
.andExpect(status().is(400));
}
}
它只是使用 MockMvc 创建请求而不是调用方法。 ObjectMapper
将我们创建的 request
转换为 Json 已作为正文发送。
您的测试从 HTTP 客户端运行的原因是因为 @Valid
批注验证了您所有的传入请求,因此您得到了正确的响应,即如果您对 careerLevel
使用的字符串长于 50,那么也是如此长字符串,如果传递 null
那么空值等
Same 在您的 junit 中不起作用,因为您正在创建 careerLevel
和设置值的普通对象。这最终会传递给 careerLevelRepository.save
.
您的 repository
正在尝试将此对象保存到数据库中并抛出 TransactionSystemException 因为输入无效并且主要是因为提交失败。
我是 Spring Boot 和 JUnit 的新手,所以我正在尝试构建一个具有如下验证约束的 Rest API:
实体class:
@Entity
public class CareerLevel {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer careerLevelId;
@NotNull
@NotEmpty
@Size(max = 50)
private String careerLevel;
// Getters and Setters
}
控制器:
@PostMapping
public ResponseEntity<CareerLevel> postCareerLevel(@RequestBody @Valid CareerLevel careerLevel) {
// saving data
CareerLevel body = careerLevelRepository.save(careerLevel);
return ResponseEntity.status(201).body(body);
}
当我使用无效值(空值、太长的字符串等)在 Insomnia(或任何其他 HTTP 客户端)上测试 post 方法时,它返回错误请求(正是我所期望的)。但是当我 运行 我的测试 class 时,它抛出了一个名为 TransactionSystemException
的异常测试方法:
@Test
void testPostCareerLevelInvalidValues() {
CareerLevel careerLevel = new CareerLevel();
careerLevel.setCareerLevel("tooLongStriiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiing");
ResponseEntity<CareerLevel> response1 = controller.postCareerLevel(careerLevel); // throwing TransactionSystemException
assertEquals(400, response1.getStatusCode().value());
}
如何处理该异常并获取响应数据?
您好,我在本地尝试了您的代码并添加了一个 lombok 注释来为实体创建一个构建器。
see @Builder
我建议在测试您的控制器时使用 MockMvc
class。
我也用mockito模拟了CareerLevelRepository
注入到CareerLevelController
@ExtendWith(MockitoExtension.class)
class CareerLevelControllerTest {
@Mock
private CareerLevelRepository careerLevelRepository;
@InjectMocks
private CareerLevelController careerLevelController;
private MockMvc mockMvc;
@BeforeEach
void setUp() {
mockMvc = MockMvcBuilders.standaloneSetup(careerLevelController)
.build();
}
private final ObjectMapper objectMapper = new ObjectMapper();
@Test
void testPostCareerLevelInvalidValues() throws Exception {
CareerLevel request = CareerLevel.builder()
.careerLevel("tooLongStriiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiing")
.build();
this.mockMvc
.perform(post("/career-levels").contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(request)))
.andExpect(status().is(400));
}
}
它只是使用 MockMvc 创建请求而不是调用方法。 ObjectMapper
将我们创建的 request
转换为 Json 已作为正文发送。
您的测试从 HTTP 客户端运行的原因是因为 @Valid
批注验证了您所有的传入请求,因此您得到了正确的响应,即如果您对 careerLevel
使用的字符串长于 50,那么也是如此长字符串,如果传递 null
那么空值等
Same 在您的 junit 中不起作用,因为您正在创建 careerLevel
和设置值的普通对象。这最终会传递给 careerLevelRepository.save
.
您的 repository
正在尝试将此对象保存到数据库中并抛出 TransactionSystemException 因为输入无效并且主要是因为提交失败。