4

mockito.spy メソッドで困っています。

私は最近、「古い」プロジェクトに到着しました。私の最初のタスクは、それにmockitoを追加し、実際の単体テストを行うことです:)

プロジェクトには多くの概念上の問題がありますが、ここでのポイントではありません ;)

私は私の問題を説明します:

クラスがあります

public class Tutu{
  public Tutu(){
  }
}

public class Toto{
  public Toto(){
  }
  public int executeToto(Tutu tutu){
    //do some stuff
    return 5;
  }
}

public class Titi{
  private Toto toto;

  public Titi(){
     this.toto = new Toto();     
  }

  public void executeTiti(){
      //do some stuff
      Tutu tutu = new Tutu();
      int ret = this.toto.executeToto(tutu);
      //do some stuff
  }
}

私のテスト クラス TitiTest.java では、executeTiti のみをテストしたいのですが、このクラスには独自のテスト クラス TotoTest.java があるため、executeToto をテストしたくありません。

しかし、ご覧のとおり、 toto はtitiコンストラクターでインスタンス化されるため、次のようなことを試します:(テストでもPowerMockを使用しているため、PowerMockRunnerを使用していますが、問題ではないようです)

@RunWith(PowerMockRunner.class)
public class TitiTest {

 @Test
 public void testExecuteTiti(){
   Toto toto = Mockito.spy(new Toto());
   Mockito.doReturn(2).when(toto).executeToto(Mockito.any(Tutu.class));

   Titi testedObject = new Titi();
   testedObject.executeTiti();
 }
}

しかし、実際のメソッドは常に呼び出しており、毎回 ret = 5 :(

私は何かが恋しいですか?私はstackoverflowでこれに関する多くの投稿を読み、すべての解決策を試しましたが、私は正しいことをしていると思うのでうまくいきません.

私はjunit4.11/powermock1.5.4/mockito1.9.5を使用しています

4

3 に答える 3

13
Toto toto = Mockito.spy(new Toto());

これは、新しく作成されたすべての Toto ではなく、この行で作成した Toto インスタンスをスパイ/スタブすることに注意してください。だからあなたが呼び出すとき:

Titi testedObject = new Titi();
testedObject.executeTiti();

コンストラクターnew Titi()自体は、Mockito の影響を受けない Toto の新しいインスタンスを作成するため、呼び出しthis.toto.executeAction()は常に 5 を返します。


PowerMockito で実行しているため、Toto のコンストラクターをスタブ化するオプションがあります。

@RunWith(PowerMockRunner.class)
@PrepareForTest(Titi.class) // stub the calling class Titi, not Toto!
public class TitiTest {
  @Test public void testExecuteTiti() {
    Toto toto = Mockito.spy(new Toto());
    Mockito.doReturn(2).when(toto).executeToto(Mockito.any(Tutu.class));

    PowerMockito.whenNew(Toto.class).withAnyArguments().thenReturn(toto);

    Titi testedObject = new Titi();
    testedObject.executeTiti();
  }
}

しかし、私が一番気に入っているオプションは、テスト用に Titi のセカンダリ コンストラクターを作成することです。

public Titi(){
  this.toto = new Toto();     
}

/** For testing only. Uses the passed Toto instance instead of a new one. */
Titi(Toto toto){
  this.toto = toto;
}

次に、次のようにテストを調整するだけで済みます。

@Test public void testExecuteTiti(){
  Toto toto = Mockito.spy(new Toto());
  Mockito.doReturn(2).when(toto).executeToto(Mockito.any(Tutu.class));

  Titi testedObject = new Titi(toto);
  testedObject.executeTiti();
}
于 2014-03-13T18:23:16.227 に答える
2

あなたが見逃しているように見えるのは、Toto クラスの Spy が実際に Titi クラスで使用されていないという事実です。

あなたの場合に私がすることは

1) コンストラクターで Toto を依存関係として受け入れるように Titi クラスをリファクタリングします。そうすれば、任意の Toto を使用して Titi を簡単に作成できます (単体テストでモックを使用するため)。

2)オプション1が問題外の場合は、次のことができます。

public class Titi{
  private Toto toto;

  public Titi(){
     this.toto = new Toto();     
  }

  public void executeTiti(){
      //do some stuff
      Tutu tutu = new Tutu();
      int ret = getToto().executeToto(tutu);
      //do some stuff
  }

  //package private - used for overriding via spying 
  Toto getToto() {
      return toto;
  }
}

@RunWith(MockitoJUnitRunner.class)
public class TitiTest {

 @Test
 public void testExecuteTiti(){
   Toto toto = Mockito.mock(Toto.class);
   when(toto.executeToto(Mockito.any(Tutu.class)).thenReturn(2);

   Titi testedObject = new Titi();
   testedObject = spy(testedObject);
   doReturn(toto).when(testedObject).getToto();

   testedObject.executeTiti();
 }
}
于 2014-03-13T18:27:12.910 に答える
0

これは、共同作業者を注入しないクラスをテストするための 1 行メソッドまたはファクトリ ヘルパー メソッドの使用について説明する記事です。https://code.google.com/p/mockito/wiki/MockingObjectCreation

于 2014-07-24T22:22:57.880 に答える