как проверить возвращаемый объект из поддельной зависимости, которая принимает два аргумента внутри поддельного объекта?

#java #unit-testing #mockito #mockmvc

#java #модульное тестирование #mockito #mockmvc

Вопрос:

Я не смог найти ни одного сообщения, связанного с моей проблемой. Я использую Mockito и хочу протестировать поведение внутри контроллера. Я думаю, что суть проблемы заключается в том, что я неправильно использую Mockito, когда отправляю два аргумента в поддельный интерфейс. Это работает нормально, если я отправляю только один аргумент. Я не думаю, что тот факт, что я также использую Spring mock mvc, имеет к этому какое-то отношение.

У меня есть интерфейс MyService :

 public MyObject doSomeDoggyStuff(long id, SomeOtherObject soo);
 

Цель интерфейса — выполнить что-то и вернуть MyObject, если он прошел успешно. Если он не может найти объект, просто верните null.

У меня есть контроллер MyController :

 @RestController
@RequestMapping(value = "/dogs")
public MyController
<snip>

 @RequestMapping(method = RequestMethod.POST, value = "/{id}/toys/{toy}")
  ResponseEntity<MyObject> doDoggyStuff(@PathVariable Long id, @RequestBody Toy toy) {
    MyObject result = this.myService.doSomeDoggyStuff(id, toy);
    if(result == null) {
       return new ResponseEntity("errorinfo", HttpStatus.NOT_FOUND);
     }
    else {
      return new ResponseEntity<MyObject>(result,HttpStatus.CREATED)'
     }
  }
 

Мой тестовый класс выглядит так:

 Public MyControllerTest <snip>

  @Mock
  private MyService myServiceMock;

  @InjectMocks
  private MyController myController;
 

Соответствующая логика метода тестирования выглядит следующим образом.

 MyObject myObj = new MyObject();
Toy toy = new Toy();

when(myServiceMock.doSomeDoggyStuff(1, toy)).thenReturn(myObj);
mockMvc
    .perform(
        post("/dogs/{id}/toys/{toys}", 1, toy).contentType(
            TestUtil.APPLICATION_JSON_UTF8).content(
            TestUtil.convertObjectToJsonBytes(toy))).andExpect(status().isCreated())
    .andReturn();
 

Проблема, с которой я сталкиваюсь, заключается в том, что в этом сценарии я ожидаю, что когда он проверяет MyController, который в строке: MyObject result = this.myService.doSomeDoggyStuff(id, toy);

результатом должен быть myObj, который я установил в thenReturn, но он всегда имеет значение null. У меня есть другие методы в моем сервисе, которые принимают только один аргумент, и он работает нормально. Я не могу понять, что мне нужно сделать по-другому, когда я отправляю два аргумента с помощью Mockito.

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

1. Вы пытались отладить то, что передается в вызов метода service на самом деле? Это может быть отсутствие реализации equals в классе Toy. Можете ли вы опубликовать код класса Toy?

Ответ №1:

Если я правильно понимаю ваши требования, вы должны использовать макет следующим образом:

when(myServiceMock.doSomeDoggyStuff(eq(1), any(Toy.class))).thenReturn(myObj);

То, как вы написали свой код, макет будет возвращаться myObj только при вызове Toy объекта, с помощью которого вы создали его экземпляр, чего никогда не бывает, поскольку Spring создаст экземпляр класса самостоятельно. Проблема не имеет ничего общего с количеством аргументов.

Однако, если вы хотите протестировать конкретный Toy , а не просто любой его экземпляр, вам нужно будет добавить equals (и, чтобы быть корректным со спецификацией, a hashCode ) метод, чтобы mockito мог сопоставить игрушки. В отсутствие какого-либо метода equals ссылки проверяются, и, конечно, они не равны, потому что экземпляры не совпадают.

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

1. Таким образом, тест не проверяет то, что хотел протестировать Магнус — он пройдет для любого игрушечного объекта. Я считаю, что проблема связана с отсутствием реализации equals в Toy.

2. @macias Вы вполне можете быть правы! Вот почему я добавил первое предложение :). Я соответствующим образом обновлю ответ

3. Спасибо вам обоим! Это прекрасно работает. Mockito — это круто, но иногда немного запутанно корректировать синтаксис для определенных сценариев.

Ответ №2:

Вам нужно либо реализовать equals в вашей игрушке, либо использовать ArgumentCaptor для проверки деталей переданного объекта. В противном случае (как уже упоминалось geoand) вы сравниваете ссылки.