Обработка моего пользовательского исключения в тесте интеграции Spring MVC - PullRequest
0 голосов
/ 03 января 2019

У меня есть следующий метод в классе контроллера:

@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), когда я вручную тестирую метод, я получаю стандартное сообщение REST с весенней загрузкой по умолчанию с полями timestamp, status, error, message и path.

Я все еще знакомлюсь с тестированием весной, и у меня есть этот тест:

@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, но фактический объект ошибки JSON не был получен объектом MockMvc.

Update2 : Вот мои аннотации на уровне класса для тестового класса:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = RfidEmployeeApplication.class)
@AutoConfigureMockMvc
@AutoConfigureTestDatabase
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@TestPropertySource(locations = "classpath:application-test.properties")

1 Ответ

0 голосов
/ 09 января 2019

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());
например.
...