代码之家  ›  专栏  ›  技术社区  ›  logi0517

在SpringMVC集成测试中处理自定义异常

  •  1
  • logi0517  · 技术社区  · 7 年前

    我在控制器类中有以下方法:

    @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) 行,当我手动测试该方法时,会得到带有时间戳、状态、错误、消息和路径字段的默认SpringBootRest消息。

    我仍然熟悉春天的测试,我有这个测试:

    @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错误对象。

    更新2 :以下是测试类的类级注释:

    @RunWith(SpringRunner.class)
    @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = RfidEmployeeApplication.class)
    @AutoConfigureMockMvc
    @AutoConfigureTestDatabase
    @FixMethodOrder(MethodSorters.NAME_ASCENDING)
    @TestPropertySource(locations = "classpath:application-test.properties")
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   borino    7 年前

    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());
    
    例如。