Тестирование контроллера POST-запроса с помощью mockito

#java #post #request #mockito #response

#java #Публикация #запрос #mockito #ответ

Вопрос:

Я пытаюсь проверить, действительно ли объект, который клиент отправляет на сервер, добавляется в базу данных контроллером с mockito. Итак, я хочу проверить ответ сервера и действительно ли отправленный объект сохраняется в db. Вот что у меня есть с точки зрения кода =

Мой тест:

 @RunWith(SpringRunner.class)
@WebMvcTest(UserController.class)
public class UserControllerTest
{
@Autowired
private MockMvc mockMvc;

@MockBean
private UserRepository userRepository;

@Test
public void testAddUserToDb() throws Exception
{
    User objToAdd = new User();
    objToAdd.setId(1);
    objToAdd.setUserID(3);
    objToAdd.setScore(55);
    objToAdd.setName("Tom");

    Gson gson = new Gson();
    String jsonString = gson.toJson(objToAdd);

    when(userRepository.save(any(User.class))).thenReturn(objToAdd);

    mockMvc.perform(post("/user/add").contentType(MediaType.APPLICATION_JSON_UTF8).content(jsonString))
            .andExpect(status().isOk())
            .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
            .andExpect(jsonPath("$.id").value(1))
            .andExpect(jsonPath("$.userID").value(3))
            .andExpect(jsonPath("$.score").value(55))
            .andExpect(jsonPath("$.name").value("Tim"));

    ArgumentCaptor<User> userArgumentCaptor = ArgumentCaptor.forClass(User.class);
    verify(userRepository, times(1)).save(userArgumentCaptor.capture());
    verifyNoMoreInteractions(userRepository);

    User userArgument = userArgumentCaptor.getValue();
    assertEquals(is(1), userArgument .getId());
    assertEquals(is("Tom"), userArgument .getName());
    assertEquals(is(3), userArgument .getUserID());
    assertEquals(is(55), userArgument .getScore());
}
}
  

Мой метод контроллера:

 @RestController
@RequestMapping("/user")
public class UserController
{
@Autowired
private UserRepository userRepository;

@PostMapping("/add")
public ResponseEntity AddUser(@RequestBody User user) throws Exception
{
    userRepository.save(user);
    return ResponseEntity.ok(HttpStatus.OK);
}
}
  

Журнал ошибок:

 MockHttpServletRequest:
  HTTP Method = POST
  Request URI = /user/add
   Parameters = {}
      Headers = [Content-Type:"application/json;charset=UTF-8"]
         Body = {"id":1,"userID":3,"name":"veg","score":55}
Session Attrs = {}

... not so important code later ...

MockHttpServletResponse:
       Status = 200
Error message = null
      Headers = [Content-Type:"application/json;charset=UTF-8"]
 Content type = application/json;charset=UTF-8
         Body = "OK"
Forwarded URL = null
   Redirected URL = null
          Cookies = []

java.lang.AssertionError: No value at JSON path "$.id"

at org.springframework.test.util.JsonPathExpectationsHelper.evaluateJsonPath(JsonPathExpectationsHelper.java:295)
at org.springframework.test.util.JsonPathExpectationsHelper.assertValue(JsonPathExpectationsHelper.java:98)
at org.springframework.test.web.servlet.result.JsonPathResultMatchers.lambda$value$2(JsonPathResultMatchers.java:111)
at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:195)
at spring.controller.UserControllerTest.AddUser(UserControllerTest.java:59)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
  

Ответ №1:

Ожидания (строка типа .andExpect(jsonPath("$.id").value(1)) ) используются для проверки ответа, а не запроса. Ваш ответ просто 200 OK без тела ответа (в соответствии с вашим контроллером).

Следующее должно работать правильно:

 mockMvc.perform(post("/user/add")
    .contentType(MediaType.APPLICATION_JSON_UTF8)
    .content(jsonString))
    .andExpect(status().isOk());
  

Комментарии:

1. Правда ли, что эта часть .content(jsonString)) проверяет запрос от клиента, а эта часть .andExpect(status().isOk()) проверяет отправленный ответ?

2. Да, все вещи внутри perform() связаны с запросом, а ожидания связаны с ответом

3. И если бы я должен был ответить объектом, используя ResponseEntity, то как я должен это протестировать. Итак, например, у меня есть следующий код в моем контроллере: @PostMapping("/add") public ResponseEntity AddUser(@RequestBody User user) throws Exception { userRepository.save(user); return ResponseEntity<User>(user, HttpStatus.OK); }

4. Затем вы можете использовать «expects» с сопоставителями результатов (как вы делали изначально)

5. Хорошо, теперь я это понимаю. Большое спасибо за вашу помощь 🙂