2013-11-13 1 views
11

Посмотрев на код ниже, я ожидаю, что вызов getSand() произойдет один раз, но тест не работает с четырьмя вызовами на него. Где происходят эти звонки? Я хочу написать тест, чтобы убедиться, что только один вызов сделан в getSand().Mockito: Проверить Mock (с помощью «RETURNS_DEEP_STUBS») Возвращает больше вызовов, чем ожидалось

Источник

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

уроки

Если вы думаете о глубоких заглушках как о древе макетных объектов, то вы должны только проверять листья («последний макет в цепочке»), потому что узлы включены в цепочку вызовов, необходимую для настройки поведения листьев , Чтобы выразить это другим способом, узлы - это, называемые во время настройки листьев.

ответ

9

Он рассчитывает вашу установку, как заклятий, так Пучина пней является not supported in the verification 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); 
... 
+0

Это странно, любая идея, почему она рассчитывает настройку? –

+0

Я думаю, что из-за того, что многие другие уже говорят, API проверки не поддерживает глубокие заглушки, поэтому он не может отличаться от реального вызова и пропущенного вызова: http://docs.mockito.googlecode.com/hg/org/ mockito/Mockito.html # RETURNS_DEEP_STUBS – crunchdog

+0

Ну, это отстой ..... – nterry

0

Из документа: «API проверки не поддерживает« цепочку », поэтому глубокий заглушка не изменяет порядок верификации».

Источник: http://mockito.googlecode.com/svn/tags/1.8.3/javadoc/org/mockito/Mockito.html#RETURNS_DEEP_STUBS

+1

I я использую Mockito 1.9.5, который больше не имеет этого предупреждения. (http://docs.mockito.googlecode.com/hg/latest/org/mockito/Mockito.html#RETURNS_DEEP_STUBS) –

7

Из документации 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, Добролюбов и РОУ и не проверить вызов getSand(). - Это зависит от того, что именно вы хотите проверить здесь.

+0

Вот как работают глубокие заглушки внутри. (Http://docs.mockito.googlecode.com/hg/latest/org/mockito/Mockito.html#RETURNS_DEEP_STUBS). Основываясь на ответе crunchdog, я считаю, что теперь вопрос: почему он подсчитывает, когда заявления как вызовы? –

+0

Ах да, но в вашем случае вы активно вызываете getSand() на первый макет несколько раз. Так что я думаю, это так. И документ несколько раз утверждает, что проверка работает только на последнем издевательстве в цепочке. – hagbard

+0

в 'verify (mockSandBox, times (1)). GetSand();' mockSandbox ** - это последний макет в цепочке. Я не уверен, что вы подразумеваете. –

Смежные вопросы