我对 Spring Boot 和 JUnit 还是很陌生,所以我尝试构建一个带有验证约束的 Rest API,如下所示:
实体类:
@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 客户端)上使用无效的 values(null、太长的字符串等)测试 post 方法时,它返回了错误的请求(完全符合我的预期)。但是当我运行我的测试类时,它抛出了一个名为 TransactionSystemException 的异常
测试方法:
@Test
void testPostCareerLevelInvalidValues() {
CareerLevel careerLevel = new CareerLevel();
careerLevel.setCareerLevel("tooLongStriiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiing");
ResponseEntity<CareerLevel> response1 = controller.postCareerLevel(careerLevel); // throwing TransactionSystemException
assertEquals(400, response1.getStatusCode().value());
}
如何处理该异常并获取响应数据?
回答1
嗨,我在本地尝试了您的代码并添加了一个 lombok 注释来为实体创建一个构建器。
https://projectlombok.org/features/Builder @Builder
我建议在测试控制器类时使用 MockMvc
。
我还使用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。
回答2
您的测试从 HTTP 客户端运行的原因是因为 @Valid
注释验证了所有传入请求,因此您得到了正确的响应,即如果您对 careerLevel
使用比 50 更长的字符串,那么字符串太长,如果传递 null
然后空 value 等。
同样在您的 junit 中不起作用,因为您正在创建 careerLevel
的普通对象并设置 value。这最终将传递给 careerLevelRepository.save
。
您的 repository
正在尝试将此对象保存到数据库中并抛出 https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/TransactionSystemException.html 因为输入无效并且主要是因为提交失败。