Я постараюсь дать вам некоторые рекомендации, которые могут вам помочь:
Удалить этот статический список и определение кандидата из файла класса модульного теста. Это создает путаницу, потому что тесты должны быть изолированы друг от друга, и при этом у вас есть объект-кандидат, общий для всех тестов. Просто исправьте это, создав статический метод getATestCandidate () в вашем тестовом классе, который каждый раз дает вам новый Candidate (). (Проверьте статические члены по сравнению со статическими методами в Java). Если позже вы увидите, что у вас есть другие тестовые классы, которым нужен Candidate, переместите этот метод в отдельный класс Util и вызовите его из других тестов или, что еще лучше, создайте класс Builder для вашего Candidate. (Проверьте шаблон проектирования Builder).
С тестовой средой Spring MVC у вас есть возможность проверить всю инфраструктуру конечных точек, включая коды состояния HTTP, сериализацию ввода и вывода, тело ответа, перенаправления и т. Д. Не отклоняйтесь от этого, проверяя несущественные вещи: В первой части теста findByIdOk () вы тестируете свой собственный макет.
4. when(candidateService.findById(candidate.getId())).thenReturn(candidate);
5. Candidate cand=candidateService.findById(candidate.getId());
6. int idCand=cand.getId();
7. assertEquals(idCand,1);
Не забывайте фундаментальную концепцию модульных тестов AAA (Arrange, Act, Assert), которая также применяется к тестам MVC. Это должно быть частью упорядочения теста, где вы настраиваете вашего сотрудника-контроллера (андидат-служба) для возврата кандидата при вызове по идентификатору. Первая строка в порядке, но вызывать ее и проверять, что id равен 1, бесполезно, потому что вы дали команду макету вернуть этого кандидата, а теперь вы проверяете, что он его возвращает? (Вы должны доверять Mockito, что он это делает) => Удалить строки 2, 3 и 4 из findByIdOk ().
Еще одним усовершенствованием метода теста findByIdOk () было бы использование свободно используемого API Mock MVC для проверки вашего статуса и содержания ответов.
Таким образом, ваш метод поиска по идентификатору может стать (проверьте пункт 3, чтобы понять, почему я переименовал идентификатор):
@Test
public void shouldReturnCandidateById() throws Exception {
//ARRANGE
Candidate candidate = getATestCandidate();
when(candidateService.findById(candidate.getId())).thenReturn(candidate);
RequestBuilder requestBuilder = get(
"/candidates/" + candidate.getId()).accept(
MediaType.APPLICATION_JSON);
//ACT
MvcResult result = mockMvc.perform(requestBuilder).
//ASSERT
.andExpect(status().is(200))
.andExpect(jsonPath("$.id", is(candidate.getId())))
...
//here you are checking whether your controller returns the
//correct JSON body representation of your Candidate resource
//so I would do jsonPath checks for all the candidate fields
//which should be part of the response
}
Предпочтительнее проверять поля json с помощью пути json отдельно, чем проверять все тело json в целом.
Теперь подумайте о разнице между проверкой того, что ваш фиктивный сотрудник CandidateService возвращает кандидата с идентификатором 1, когда вы уже проинструктировали его об этом (это ничего не доказывало), и проверкой того, что ваш контроллер может вернуть кандидата Представление ресурса в виде JSON со всеми полями-кандидатами внутри него при запросе на конкретный идентификатор кандидата.
- Поскольку у вас, вероятно, будет несколько методов тестирования для одной и той же конечной точки контроллера, назовите свои методы тестирования, чтобы объяснить, что именно вы пытаетесь проверить. Таким образом, вы документируете свои тесты, и они также станут ремонтопригодными. Позже кому-то другому будет действительно легко понять, что должен делать тест и как его исправить, если он сломался. Хорошей практикой является использование соглашения об именах во всем приложении.
Например,
В вашем конкретном классе Test вместо создания теста
@Test
public void findAll() {
...
}
создайте имя с более внушительным именем, которое также включает ресурс, которым вы манипулируете
@Test
public void shouldGetCandidatesList() {
...
}
или
@Test
public void shouldReturn404NotFoundWhenGetCandidateByIdAndItDoesntExist() {
...
}
- Теперь перейдем к удалению конечной точки и реализации сервиса. Вы можете поместить вызов service.deleteById () в блок try catch, перехватить исключение ResourceNotFound и вернуть из вашего контроллера 404.
Ваша служба удаления может выглядеть так, потому что вы знаете, что API службы должен выдавать ResourceNotFoundException, если вы пытаетесь удалить кандидата, которого не существует:
@DeleteMapping("/candidates/{id}")
public ResponseEntity<Void> deleteCandidate(@PathVariable int id) {
try{
candidateService.deleteById(id);
} catch(ResourceNotFoundException e) {
ResponseEntity.notFound().build()
}
return ResponseEntity.noContent().build();
}
Теперь вам нужно выполнить тест, который проверяет, что ваш контроллер возвращает Not found при вызове конечной точки удаления с несуществующим идентификатором кандидата.Для этого вы проинструктируете в своем тесте фиктивного соавтора (candidService) возвращать ноль при вызове этого идентификатора.Не попадайтесь в ловушку повторного выполнения каких-либо утверждений на вашем поддельном сервисе кандидата.Цель этого теста - убедиться, что ваша конечная точка возвращает NotFound при вызове с несуществующим идентификатором кандидата.
Ваш скелет теста shouldReturnNotFoundWhenGetCandidateByNonExistingId ()
@Test
public void shouldReturnNotFoundWhenGetCandidateByNonExistingId() {
//the Arrange part in your test
doThrow(new ResourceNotFoundException(candidate.getId())).when(candidateService).deleteById(anyInt());
//call mockMvc
//assert not found using the MockMvcResultMatchers
}
Пожалуйста, адаптируйте свои тесты для полученияконечные точки, чтобы также проверить тело JSON.Наличие теста, который проверяет только состояние, когда конечная точка возвращает также некоторое тело ответа, завершено только наполовину.
Пожалуйста, ознакомьтесь с документацией о том, как структурировать конечные точки.То, что вы сделали здесь, возможно, работает и компилируется, но это не значит, что это правильно.Я ссылаюсь на это ("/ кандидаты / имя / {имя}", "/ кандидаты / создать").