2010-07-26 4 views
4

У меня возникла проблема с ArgumentCaptor, которая не может записывать аргументы при вызове того же метода несколько раз. В принципе, это не похоже на работу:Проблема с ArgumentCaptor и последовательный вызов тех же методов (ошибка или функция?)

List<Dummy> mList = mock(List.class); 
Dummy dummy = new Dummy(); 
when(mList.get(anyInt())).thenReturn(dummy); 

Dummy d = mList.get(12); 
d.setName("John"); 
mList.add(d); 

Dummy g = mList.get(10); 
g.setName("Ben"); 
mList.add(g); 
... 

verify(mymock, times(3)).doStuff(captor.capture)); 
assertEquals("John", captor.getAllValues().get(0).getName()); 
assertEquals("Ben", captor.getAllValues().get(1).getName()); 
assertEquals("Don", captor.getAllValues().get(2).getName()); 

Значение GetName() всегда устанавливается на «Дон». Я также пробовал использовать InOrder с тем же результатом.

Функция (и мне stupiud) или ошибка?

Чтобы лучше объяснить этот вопрос я создал прецедент: http://pastebin.com/RE1UzJ4F

Приветствия

ответ

2

Java-документ для ArgumentCaptor предполагает, что вы пытаетесь, так что я бы сказал, что это ошибка. Однако это ошибка в коде.

Проблема в том, что вы меняете имя того же манекена каждый раз, когда вы вызываете setName (..). Я бы предположил, что вы делаете Dummy неизменным и избегайте сеттеров везде, где сможете. Это позволит избежать подобных ошибок.

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

when(mList.get(anyInt())).thenReturn(new Dummy(), new Dummy(), new Dummy()); 

Исправить проблему.

+0

Да, конечно, тестовый код был просто способ объяснить проблему. –

+1

Могу сказать, что единственная проблема на самом деле в вашем коде, а не в Mockito. Это то, что вы пытались объяснить (в этом случае мне жаль, что я пропустил это)? – iwein

+0

Я исправил ваш образец в pastebin (без компиляции, хотя). – iwein

2

iwein является правильным; однако есть некоторые ситуации (например, встроенные системы), в которых недостаточно памяти, и вы не хотите использовать или не можете использовать неизменность.

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

List<Mock> mocks = new ArrayList<Mock>(); 
...init list w/ mocks using for loop... 
List<Object[]> expectedArgs = new ArrayList<Object[]>(); 
..init list w/ desired args... 

mocks.get(0).callMethod(1, 2); 
...do that some more... 

for(int i = 0; i < mocks.size(); i++) { 
    Object[] desiredArgs = expectedArgs.get(i); 
    verify(mocks.get(i)).callMethod((int) desiredArgs[0], (int) desiredArgs[1]); 
} 

Это не так красиво, но вам не нужно делать ваши классы неизменными таким образом.

0

Я имел эту проблему и в конечном итоге с помощью atLeastOnce, например, так:

private ActionRequest getRequestedAction() { 
    ArgumentCaptor<ActionRequest> captor = ArgumentCaptor.forClass(ActionRequest.class); 
    verify(adapter, atLeastOnce()).requestAction(captor.capture()); 
    return captor.getValue(); 
}