Как использовать thenAnswer с методом, который возвращает void

Я хочу провести модульное тестирование следующим методом

public void addRecord(Record record)  
{  
   Myclass newObj = new Mycalss();  
   // It creates newObj object, set some values using record object.  
   // and it adds the newObj in daatbase.
   dataReqDao.persist(newObj);
}    

Я издевался над методом dataReqDao.persist, но как я могу проверить, скопированы ли правильные значения в объект newObj? Я хочу получить объект newObj.

Я думаю, что thenAnswer будет подходящим методом для получения аргументов метода newObj ie, но не знаю, как использовать этот метод, который возвращает void.

Обновление:
я пытался

doAnswer(new Answer<Myclass>() {
              public Myclass answer(InvocationOnMock invocation) {
                  Object[] args = invocation.getArguments();
                  return (Myclass)args[0];
              }

        }).when(dataReqDao.persist(any(Myclass.class)));

EDIT:
Так и должно быть (спасибо, Дэвид)

 doAnswer(new Answer<Myclass>() {
                  public Myclass answer(InvocationOnMock invocation) {
                      Object[] args = invocation.getArguments();
                      return (Myclass)args[0];
                  }

            }).when(dataReqDao).persist(any(Myclass.class));

person Ajinkya    schedule 06.01.2012    source источник
comment
В вашем обновлении скобки не на месте. Я не уверен, что это причина вашей ошибки, потому что все остальное выглядит нормально. Так должно быть doAnswer( ... ).when( dataReqDao ).persist( ... ); Это помогает?   -  person Dawood ibn Kareem    schedule 11.01.2012
comment
@David: Спасибо, Дэвид. На самом деле я исправил это, но забыл обновить свой вопрос.   -  person Ajinkya    schedule 11.01.2012


Ответы (3)


Вы можете создать собственный сопоставитель аргументов, который проверял бы поля этого объекта или использовал ссылку захват аргументов для захвата объекта для дальнейшей проверки.

Например, следующим образом:

ArgumentCaptor<Myclass> c = ArgumentCaptor.forClass(Myclass.class);
verify(dateReqDao).persist(c.capture());
Myclass newObj = c.getValue();

... // Validate newObj
person axtavt    schedule 06.01.2012
comment
Это не является умным тестом, так как ArgumentCaptor фиксирует не это состояние объекта во время вызова, а только objectId. Таким образом, даже если вы используете сеттеры в своем методе после вызова dao, ваш тест будет зеленым. Но хороший тест должен давать сбой при каждом функциональном изменении. Я написал свое предложение в качестве ответа на пост. - person akcasoy; 10.04.2015

Вам нужно сделать это с помощью thenAnswer (или thenAnswer, что я лично предпочитаю), чтобы вы могли утверждать/проверять значения во время вызова метода в методе.

 when(dataReqDao.persist(newObj)).then(new Answer<Void>() {
        @Override
        public Void answer(final InvocationOnMock invocation) {
            Myclass newObjActual = (Myclass) invocation.getArguments()[0];

            // Control
            assertEquals(..., newObjActual.getX());
            assertEquals(..., newObjActual.getY());
            return null;
        }
    });

 // Run Test
 x.addRecord(record);

Вот подробное объяснение: https://akcasoy.wordpress.com/2015/04/09/the-power-of-thenanswer/ (вариант использования 2)

ArgumentCaptor не тестирует умным способом. Когда вы меняете свой метод следующим образом:

public void addRecord(Record record)  
{  
   Myclass newObj = new Mycalss();  
   dataReqDao.persist(newObj);

   // first persist, than set attributes
   newObj.setX(..);
}  

.. ваш тест с Captor все еще выполняется, но он должен завершиться неудачно. Поскольку ArgumentCaptor фиксирует не это состояние объекта во время вызова, а только objectId, для захвата не имеет значения, устанавливаете ли вы свои атрибуты до или после вызова dao. Тем не менее, хороший тест должен давать сбой при каждом функциональном изменении. Вот моя статья как раз про этот случай:

https://akcasoy.wordpress.com/2015/02/03/how-to-ensure-quality-of-junit-tests/ (приведенная выше заглушка с помощью then является лучшим подходом, чем подход с InOrder подход)

person akcasoy    schedule 10.04.2015

Myclass newObj = new Myclass();  

Меня беспокоит эта линия. Если вы используете внедрение зависимостей, ваша фабрика должна отправить вам экземпляр этого объекта. Затем, когда вы создаете свои модульные тесты, вы можете отправить тестовой фабрике фиктивный экземпляр MyClass, к которому модульный тест также может иметь доступ. Затем вы можете использовать captor axtavt, чтобы увидеть, действительно ли он сделал то, что должен был сделать. Нет ничего плохого в модульном тесте в том виде, в котором вы его сделали, просто any() является слабым, учитывая, что вы знаете, что он передает объект этого типа - что вы хотите знать в тесте, является ли объект тот, который вы намеревались и не был изменен.

person Community    schedule 17.01.2012