Mockito: проверка макета (с помощью "RETURNS_DEEP_STUBS" ) Возвращает больше вызовов, чем ожидалось
Глядя на код ниже, я ожидаю, что вызов getSand()
произойдет один раз, но тест не работает с четырьмя вызовами. Где происходят эти звонки? Я хочу написать тест, чтобы гарантировать, что для getSand()
выполняется только один вызов.
Источник
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class DeepSandTest {
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
SandBox mockSandBox;
@Test
public void should(){
when(mockSandBox.getSand().doA()).thenReturn(1);
when(mockSandBox.getSand().doB()).thenReturn(1);
when(mockSandBox.getSand().doC()).thenReturn(1);
DeepSand deepSand = new DeepSand(mockSandBox);
deepSand.getTipple();
verify(mockSandBox, times(1)).getSand();
}
public class DeepSand{
private SandBox sandBox;
public DeepSand(SandBox sandBox) {
this.sandBox = sandBox;
}
public void getTipple(){
Sand sand = sandBox.getSand();
sand.doA();
sand.doB();
sand.doC();
}
}
public interface SandBox{
public Sand getSand();
}
public interface Sand{
public Integer doA();
public Integer doB();
public Integer doC();
}
}
Выход
org.mockito.exceptions.verification.TooManyActualInvocations:
mockSandBox.getSand();
Wanted 1 time:
-> at DeepSandTest.should(DeepSandTest.java:26)
But was 4 times. Undesired invocation:
-> at DeepSandTest.should(DeepSandTest.java:20)
Подробнее Java 1.6, JUnit 4.11, Mockito 1.9.5
Извлеченные уроки
Если вы думаете о глубоких заглушках как о древе макетных объектов, тогда вы должны только проверять листья ( "последний макет в цепочке" ), потому что узлы включены в цепочку вызовов, необходимую для настройки поведения листьев. Чтобы выразить это другим способом, узлы вызываются во время установки листьев.
Ответы
Ответ 1
Он подсчитывает вашу настройку как invocations, так как глубокие заглушки не поддерживается в API проверки и жалуется на второй вызов, который:
when(mockSandBox.getSand().doB()).thenReturn(1);
Я бы пропустил использование RETURNS_DEEP_STUBS и просто использовал другой макет:
...
@Mock
SandBox mockSandBox;
@Mock
Sand sand;
@Test
public void should(){
when(mockSandBox.getSand()).thenReturn(sand);
when(sand.doA()).thenReturn(1);
when(sand.doB()).thenReturn(1);
when(sand.doC()).thenReturn(1);
...
Ответ 2
Из документации Answers.RETURNS_DEEP_STUBS:
Please see the {@link org.mockito.Mockito#RETURNS_DEEP_STUBS} documentation for more details.
От Mockito.RETURNS_DEEP_STUBS:
Verification only works with the last mock in the chain. You can use verification modes.
[...]
when(person.getAddress(anyString()).getStreet().getName()).thenReturn("deep");
[...]
inOrder.verify(person.getAddress("the docks").getStreet(), times(1)).getName();
Итак, я думаю, чтобы заставить ваши проверки работать, вы должны переписать свои Mocks на что-то вроде этого:
@Mock
SandBox mockSandBox;
@Mock
Sand mockSand;
@Test
public void should()
{
when( mockSand.doA() ).thenReturn( 1 );
when( mockSand.doB() ).thenReturn( 1 );
when( mockSand.doC() ).thenReturn( 1 );
when( mockSandBox.getSand() ).thenReturn( mockSand );
DeepSand deepSand = new DeepSand( mockSandBox );
deepSand.getTipple();
verify( mockSandBox, times( 1 ) ).getSand();
}
Или проверяйте только вызовы doA, doB и doC и не проверяйте вызов getSand(). - Это зависит от того, что именно вы хотите проверить здесь.
Ответ 3
Из документа:
"API проверки не поддерживает" цепочку ", поэтому глубокий заглушка не изменяет порядок верификации.
Источник: http://mockito.googlecode.com/svn/tags/1.8.3/javadoc/org/mockito/Mockito.html#RETURNS_DEEP_STUBS