Java Mockito:验证模拟(使用“RETURNS_DEEP_STUBS”)返回的调用数超出预期

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19963622/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 21:51:47  来源:igfitidea点击:

Mockito: Verify Mock (with "RETURNS_DEEP_STUBS") Returns More Calls Than Expected

javamockito

提问by Mike Rylander

Looking at the code below, I only expect the call to getSand()to happen once, but the test is failing with four calls to it. Where are these calls happening? I want to write a test to insure that only one call is made to getSand().

看看下面的代码,我只希望调用getSand()发生一次,但测试失败了,有四次调用。这些电话在哪里发生?我想编写一个测试来确保只对getSand().

Source

来源

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();
    }
}

Output

输出

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)

DetailsJava 1.6, JUnit 4.11, Mockito 1.9.5

详细信息Java 1.6、JUnit 4.11、Mockito 1.9.5

Lessons Learned

得到教训

If you think of deep stubs as a tree of mock objects, then you should only verify the leaves ("last mock in the chain") because the nodes are included in the call chain needed to setup the behavior of the leaves. To phrase this another way, the nodes arecalled during the setup of the leaves.

如果您将深存根视为模拟对象树,那么您应该只验证叶子(“链中的最后一个模拟”),因为节点包含在设置叶子行为所需的调用链中。换句话说,节点在叶子的建立期间调用。

采纳答案by crunchdog

It's counting your setup as invocations since deeps stubs is not supported in the verification API, and complains on the second call which is:

由于验证 API 不支持深度存根,因此将您的设置计为调用,并在第二次调用时抱怨:

when(mockSandBox.getSand().doB()).thenReturn(1);

I would skip using RETURNS_DEEP_STUBS and just use another mock:

我会跳过使用 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);
...

回答by Areo

From documention: " Verification API does not support 'chaining' so deep stub doesn't change how you do verification."

来自文档:“验证 API 不支持‘链接’,因此深存根不会改变您进行验证的方式。”

Source: http://mockito.googlecode.com/svn/tags/1.8.3/javadoc/org/mockito/Mockito.html#RETURNS_DEEP_STUBS

来源:http: //mockito.googlecode.com/svn/tags/1.8.3/javadoc/org/mockito/Mockito.html#RETURNS_DEEP_STUBS

回答by hagbard

From the documentation of Answers.RETURNS_DEEP_STUBS:

从 Answers.RETURNS_DEEP_STUBS 的文档中:

Please see the {@link org.mockito.Mockito#RETURNS_DEEP_STUBS} documentation for more details.

From Mockito.RETURNS_DEEP_STUBS:

来自 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();


So, I think, in order to get your verifies to work, you have to rewrite your Mocks to something like this:

所以,我认为,为了让你的验证工作,你必须将你的 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();
}


Or only verify the invocations of doA, doB and doC and not verify the invocation of getSand(). - Which depends on what exactly you want to test for here.

或者只验证 doA、doB 和 doC 的调用,而不验证 getSand() 的调用。- 这取决于您想在这里测试什么。