spring-boot - 在 Spring MVC 集成测试中处理我的自定义异常
问题描述
我在控制器类中有以下方法:
@PostMapping("employees")
@ResponseStatus(HttpStatus.CREATED)
public Employee addEmployee(@Valid @RequestBody Employee employee) {
try {
return employeeRepository.save(employee);
} catch (DataIntegrityViolationException e) {
e.printStackTrace();
Optional<Employee> existingEmployee = employeeRepository.findByTagId(employee.getTagId());
if (!existingEmployee.isPresent()) {
//The exception root cause was not due to a unique ID violation then
throw e;
}
throw new DuplicateEntryException(
"An employee named " + existingEmployee.get().getName() + " already uses RFID tagID " + existingEmployee.get().getTagId());
}
}
Employee
该类有一个名为的字符串字段,其中tagId
有一个@NaturalId
注释。(请忽略没有专门的服务层,这是一个小而简单的应用程序)。
这是我的习惯DuplicateEntryException
:
@ResponseStatus(HttpStatus.CONFLICT)
public class DuplicateEntryException extends RuntimeException {
public DuplicateEntryException() {
super();
}
public DuplicateEntryException(String message) {
super(message);
}
public DuplicateEntryException(String message, Throwable cause) {
super(message, cause);
}
}
感谢这@ResponseStatus(HttpStatus.CONFLICT)
条线,当我手动测试该方法时,我得到了带有时间戳、状态、错误、消息和路径字段的默认 Spring Boot REST 消息。
我仍然熟悉 Spring 中的测试,并且我有这个测试:
@Test
public void _02addEmployee_whenDuplicateTagId_thenExceptionIsReturned() throws Exception {
Employee sampleEmployee = new Employee("tagId01", "John Doe");
System.out.println("Employees in the database: " + repository.findAll().size()); //prints 1
// @formatter:off
mvc.perform(post("/employees").contentType(MediaType.APPLICATION_JSON).content(JsonUtil.toJson(sampleEmployee)))
.andExpect(status().isConflict())
.andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.message").value("An employee named John Doe already uses RFID tagID tagId01"));
// @formatter:on
int employeeCount = repository.findAll().size();
Assert.assertEquals(1, employeeCount);
}
您可以猜到,首先运行另一个测试,称为_01addEmployee_whenValidInput_thenCreateEmployee()
,它插入一个具有相同 tagID 的员工,这在测试#2 中使用。测试 #1 通过,但测试 #2 没有通过,因为 HTTP 响应如下所示:
MockHttpServletResponse:
Status = 409
Error message = null
Headers = {}
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
在上述响应之前的控制台中,我看到了这个:
Resolved Exception:
Type = ai.aitia.rfid_employee.exception.DuplicateEntryException
所以我的第二次测试失败了,因为java.lang.AssertionError: Content type not set
. 与手动测试相比,是什么导致了不同的行为?这个怎么不退呢?
{
"timestamp": "2019-01-03T09:47:33.371+0000",
"status": 409,
"error": "Conflict",
"message": "An employee named John Doe already uses RFID tagID tagId01",
"path": "/employees"
}
更新:我在不同的 REST 端点上也遇到了同样的事情,测试用例导致了我自己的ResourceNotFoundException
,但是 MockMvc 对象没有接收到实际的 JSON 错误对象。
Update2:这是我对测试类的类级别注释:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = RfidEmployeeApplication.class)
@AutoConfigureMockMvc
@AutoConfigureTestDatabase
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@TestPropertySource(locations = "classpath:application-test.properties")
解决方案
org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#error
填写错误响应正文的完整信息,但MockMvc
它不起作用。我刚刚检查过你可以在这种情况下轻松使用TestRestTemplate
。
首先只是@Autowired private TestRestTemplate testRestTemplate;
在测试课上。
并修改您的测试方法,例如:
ResponseEntity<String> response = testRestTemplate.postForEntity("/employees", sampleEmployee, String.class);
String message = com.jayway.jsonpath.JsonPath.read(response.getBody(), "$.message");
String expectedMessage = "An employee named John Doe already uses RFID tagID tagId01";
Assert.assertEquals(expectedMessage, message);
Assert.assertTrue(response.getStatusCode().is4xxClientError());
例如。
推荐阅读
- laravel - 如何将 laravel 模型工厂创建方法返回的对象转换为包含模型字段的数组?
- python - pandas concat 重新排序的列
- boost - boost::bind 作为参数接受具有 n 个参数的函数,并在进一步的函数调用中使用相同的参数
- r - shiny::observeEvent 工作或中断的条件是什么,即隔离其参数
- cuda - CUDA surf3Dread 重载类型,只有一种有效?
- amazon-web-services - 使用预制 ACL 直接将雪花数据卸载到 S3 位置
- django - django-rest-auth google 和 facebook 注册返回访问令牌和代码
- android - 在模块 jetified-google-pay-client-api-1.0.0-runtime.jar 中发现重复的类 com.google.android.aidl.BaseProxy
- javascript - 将子组件单击处理程序绑定到父状态
- mongodb - 无法将 mongodb 服务器的远程访问权限授予在 ubuntu 上相同 wifi 网络中的其他系统