Соответствующий изменяемый объект без ArgumentCaptor - PullRequest
0 голосов
/ 25 апреля 2018

Я должен проверить метод, который использует изменяемый объект

private final List<LogMessage> buffer;
...
flushBuffer() {
  sender.send(buffer);
  buffer.clear();
}

Мне нужно проверить, что он отправляет буферы с точным размером.
ArgumentCaptor не применимо, так как собранная коллекция к моменту подтверждения очищена.

Существует ли вид сопоставления, который может повторно использовать hasSize() Hamcrest и выполняет проверку прямо во время вызова метода?

Я бы предпочел что-то вроде этого гипотетического collectionWhich matcher:

bufferedSender.flushBuffer();
verify(sender).send(collectionWhich(hasSize(5)));

Ответы [ 3 ]

0 голосов
/ 26 апреля 2018

Легкая альтернатива идее Дэвида: используйте Answer, чтобы сделать копию во время разговора.Непроверенный код, но это должно быть довольно близко:

final List<LogMessage> capturedList = new ArrayList<>();
// This uses a lambda, but you could also do it with an anonymous inner class:
// new Answer<Void>() {
//   @Override public Void answer(InvocationOnMock invocation) { /* ... */ }
// }
when(sender.send(any())).thenAnswer(invocation -> {
  List<LogMessage> argument = (List<LogMessage>) invocation.getArguments()[0];
  capturedList.addAll(argument);
});
bufferedSender.flushBuffer();
assertThat(capturedList).hasSize(5);
0 голосов
/ 29 апреля 2018

Ответ Джеффа Боумена хорош, но я думаю, что мы можем улучшить его, вставив утверждение в сам объект Answer. Это позволяет избежать создания ненужных объектов копирования и дополнительных локальных переменных.

Кроме того, в случаях, когда нам нужно копировать состояние пользовательских объектов (путем его глубокого копирования), этот способ намного проще. Действительно, для выполнения копирования не требуется никакого специального кода или библиотеки, так как утверждение выполняется на лету.

В Java 8 это даст:

import  static org.mockito.Mockito.*;

when(sender.send(any())).thenAnswer(invocation -> {
  List<LogMessage> listAtMockTime = invocation.getArguments()[0];
  Assert.assertEquals(5, listAtMockTime.getSize());
});
bufferedSender.flushBuffer();

Обратите внимание, что InvocationOnMock.getArgument(int index) возвращает неограниченный подстановочный знак (?). Таким образом, от вызывающей стороны не требуется приведение, поскольку возвращаемый тип определяется целью: здесь объявленная переменная, для которой мы присваиваем результат.

0 голосов
/ 25 апреля 2018

У вас будет та же проблема, что и с ArgumenCaptor, так как метод verify() проверяет вызов с состоянием объекта после выполнения.Захват не выполняется, чтобы сохранить только состояние во время вызова.
Так что с изменяемым объектом я думаю, что лучшим способом было бы не использовать Mockito и вместо этого создать заглушку класса Sender, где вы захватываете фактическийразмер коллекции как send() вызывается.

Вот пример класса заглушки (минимальный пример, который вы, конечно, можете обогатить / адаптировать):

class SenderStub extends Sender {

    private int bufferSize;
    private boolean isSendInvoked;

    public int getBufferSize() {
        return bufferSize;
    }

   public boolean isSendInvoked(){
      return isSendInvoked;
   }

    @Override
    public void send(List<LogMessage> buffer ) {
        this.isSendInvoked = true;
        this.bufferSize = buffer.size();
    }    
}

Теперь у вас есть способ проверить, был ли вызван Отправитель, и его размер (или даже больше) этого.

Итак, отложите Mockito для создания этого макета и проверьте его поведение:

SenderStub sender = new SenderStub();
MyClassToTest myClass = new MyClassToTest(sender);
// action
myClass.flushBuffer();
// assertion
Assert.assertTrue(sender.isInvoked()); 
Assert.assertEquals(5, sender.getBufferSize());
...