21

以下のコードを見ると、呼び出しが 1 回だけ発生すると予想されますgetSand()が、テストは 4 回の呼び出しで失敗しています。これらの通話はどこで行われていますか? への呼び出しが 1 回だけであることを保証するテストを作成したいと考えてい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

学んだ教訓

ディープ スタブをモック オブジェクトのツリーと考える場合は、リーフの動作をセットアップするために必要な呼び出しチェーンにノードが含まれているため、リーフ (「チェーンの最後のモック」) のみを検証する必要があります。別の言い方をすれば、リーフのセットアップ中にノードが呼び出されます。

4

3 に答える 3

15

deeps stubs は検証 APIでサポートされていないため、セットアップを呼び出しとしてカウントし、次の 2 番目の呼び出しで不平を言います。

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);
...
于 2013-11-13T20:41:20.967 に答える
13

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

したがって、検証を機能させるには、モックを次のように書き換える必要があると思います。

@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() の呼び出しを検証しません。- これは、ここで正確に何をテストしたいかによって異なります。

于 2013-11-13T20:38:28.597 に答える
0

ドキュメントから: 「検証 API は「連鎖」をサポートしていないため、ディープ スタブによって検証方法が変わることはありません。」

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

于 2013-11-13T20:37:11.493 に答える