432

Mockito1.9.0を使用しています。JUnitテストのクラスの単一メソッドの動作をモックしたいので、

final MyClass myClassSpy = Mockito.spy(myInstance);
Mockito.when(myClassSpy.method1()).thenReturn(myResults);

問題は、2行目でmyClassSpy.method1()実際に呼び出され、例外が発生することです。私がモックを使用している唯一の理由は、後で呼び出されるたびmyClassSpy.method1()に実際のメソッドが呼び出されず、myResultsオブジェクトが返されるようにするためです。

MyClassはインターフェースでありmyInstance、それが重要な場合はその実装です。

このスパイ行動を修正するには何をする必要がありますか?

4

10 に答える 10

735

公式ドキュメントを引用させてください:

実際のオブジェクトをスパイする際の重要な落とし穴!

when(Object)をスタブスパイに使用できない場合があります。例:

List list = new LinkedList();
List spy = spy(list);

// Impossible: real method is called so spy.get(0) throws IndexOutOfBoundsException (the list is yet empty)
when(spy.get(0)).thenReturn("foo");

// You have to use doReturn() for stubbing
doReturn("foo").when(spy).get(0);

あなたの場合、それは次のようになります:

doReturn(resultsIWant).when(myClassSpy).method1();
于 2012-07-23T20:41:36.480 に答える
37

私の場合、Mockito 2.0を使用して、実際の呼び出しをスタブするためにすべてのany()パラメーターをに変更する必要がありました。nullable()

于 2017-03-29T20:46:24.187 に答える
28

私の場合は、受け入れられた答えとは異なりました。そのパッケージに存在しないインスタンスのパッケージプライベートメソッドをモックしようとしていました

package common;

public class Animal {
  void packageProtected();
}

package instances;

class Dog extends Animal { }

とテストクラス

package common;

public abstract class AnimalTest<T extends Animal> {
  @Before
  setup(){
    doNothing().when(getInstance()).packageProtected();
  }

  abstract T getInstance();
}

package instances;

class DogTest extends AnimalTest<Dog> {
  Dog getInstance(){
    return spy(new Dog());
  }

  @Test
  public void myTest(){}
}

コンパイルは正しいですが、テストをセットアップしようとすると、代わりに実際のメソッドが呼び出されます。

メソッドを保護またはパブリックとして宣言すると、問題が修正されますが、これはクリーンなソリューションではありません。

于 2016-08-02T10:43:03.880 に答える
20

Tomasz Nurkiewiczの答えは、全体像を示しているわけではないようです。

NB Mockitoバージョン:1.10.19。

私は非常にMockitoの初心者なので、次の動作を説明することはできません。この回答を改善できる専門家がいる場合は、お気軽にどうぞ。

ここで問題となっているメソッドはgetContentStringValueNOT finalおよびNOT staticです。

この行元のメソッドを呼び出しますgetContentStringValue

doReturn( "dummy" ).when( im ).getContentStringValue( anyInt(), isA( ScoreDoc.class ));

この行は元のメソッドを呼び出しませんgetContentStringValue

doReturn( "dummy" ).when( im ).getContentStringValue( anyInt(), any( ScoreDoc.class ));

答えられない理由で、を使用するisA()と、意図された(?)「メソッドを呼び出さない」動作がdoReturn失敗します。

ここに含まれるメソッドシグネチャを見てみましょう。どちらものstaticメソッドですMatchers。どちらもJavadocによって返されると言われていnullますが、それ自体で頭を動かすのは少し難しいです。おそらく、Classパラメータとして渡されたオブジェクトが調べられますが、結果は計算されないか、破棄されません。これは任意のクラスを表すことnullができ、モックされたメソッドが呼び出されないことを望んでいることを考えると、ジェネリックパラメーターではなくのシグネチャisA( ... )any( ... )返すことができませんでした* ?null<T>

ともかく:

public static <T> T isA(java.lang.Class<T> clazz)

public static <T> T any(java.lang.Class<T> clazz)

APIドキュメントには、これに関する手がかりはありません。また、このような「メソッドを呼び出さない」動作の必要性は「非常にまれ」であると言っているようです。個人的に私はいつもこのテクニックを使用しています。通常、モックには「シーンを設定」する数行が含まれ、その後にメソッドを呼び出して、ステージングしたモックコンテキストでシーンを「再生」します。 。そして、あなたが風景と小道具をセットアップしている間、あなたが望む最後のことは、俳優が左のステージに入り、彼らの心を演じ始めることです...

しかし、これは私の給料等級をはるかに超えています...私は通りすがりのモッキト大祭司からの説明を招待します...

*「ジェネリックパラメータ」は正しい用語ですか?

于 2016-11-06T18:46:34.427 に答える
13

スパイで問題を引き起こす可能性のあるもう1つのシナリオは、Spring Bean(Spring Testフレームワークを使用)またはテスト中にオブジェクトをプロキシしている他のフレームワークをテストしている場合です。

@Autowired
private MonitoringDocumentsRepository repository

void test(){
    repository = Mockito.spy(repository)
    Mockito.doReturn(docs1, docs2)
            .when(repository).findMonitoringDocuments(Mockito.nullable(MonitoringDocumentSearchRequest.class));
}

上記のコードでは、SpringとMockitoの両方がMonitoringDocumentsRepositoryオブジェクトをプロキシしようとしますが、Springが最初になり、findMonitoringDocumentsメソッドが実際に呼び出されます。リポジトリオブジェクトにスパイを配置した直後にコードをデバッグすると、デバッガー内では次のようになります。

repository = MonitoringDocumentsRepository$$EnhancerBySpringCGLIB$$MockitoMock$

@SpyBeanが救助に

代わりに@Autowiredアノテーションを使用する場合@SpyBean、上記の問題を解決します。SpyBeanアノテーションもリポジトリオブジェクトを挿入しますが、最初にMockitoによってプロキシされ、デバッガー内で次のようになります。

repository = MonitoringDocumentsRepository$$MockitoMock$$EnhancerBySpringCGLIB$

そしてここにコードがあります:

@SpyBean
private MonitoringDocumentsRepository repository

void test(){
    Mockito.doReturn(docs1, docs2)
            .when(repository).findMonitoringDocuments(Mockito.nullable(MonitoringDocumentSearchRequest.class));
}
于 2018-10-08T14:10:11.677 に答える
2

スパイが元のメソッドを呼び出すもう1つの理由を見つけました。

誰かがfinalクラスをモックするという考えを持っていて、それについて見つけましたMockMaker

これは現在のメカニズムとは異なる動作をし、これには異なる制限があり、経験とユーザーフィードバックを収集したいので、この機能を使用可能にするには明示的にアクティブ化する必要がありました。src/test/resources/mockito-extensions/org.mockito.plugins.MockMakerこれは、1行を含むファイルを作成することにより、mockito拡張メカニズムを介して実行できます。mock-maker-inline

ソース:https ://github.com/mockito/mockito/wiki/What%27s-new-in-Mockito-2#mock-the-unmockable-opt-in-mocking-of-final-classesmethods

そのファイルをマージしてマシンに持ってきた後、テストは失敗しました。

行(またはファイル)を削除するだけで、spy()作業を完了しました。

于 2018-01-17T11:57:27.653 に答える
2

実際のオブジェクトをスパイする際の重要な落とし穴

スパイを使用してメソッドをスタブする場合は、 doReturn()ファミリーのメソッドを使用してください。

when(Object)は、例外をスローできる実際のメソッドを呼び出す結果になります。

List spy = spy(new LinkedList());

//Incorrect , spy.get() will throw IndexOutOfBoundsException   
 when(spy.get(0)).thenReturn("foo");

//You have to use doReturn() for stubbing    
doReturn("foo").when(spy).get(0);
于 2021-11-30T14:43:43.250 に答える
0

クラスのメソッドが呼び出されないようにする1つの方法は、メソッドをダミーでオーバーライドすることです。

    WebFormCreatorActivity activity = spy(new WebFormCreatorActivity(clientFactory) {//spy(new WebFormCreatorActivity(clientFactory));
            @Override
            public void select(TreeItem i) {
                log.debug("SELECT");
            };
        });
于 2018-06-19T21:28:36.753 に答える
0

いくつかのコメントで述べたように、私のメソッドは「静的」でした(クラスのインスタンスによって呼び出されましたが)

public class A {
  static void myMethod() {...}
}
A instance = spy(new A());
verify(instance).myMethod(); // still calls the original method because it's static

回避策は、インスタンスメソッドを作成するか、いくつかの構成を使用してMockitoを新しいバージョンにアップグレードすることでした:https ://stackoverflow.com/a/62860455/32453

于 2021-10-04T19:01:52.207 に答える
-1

パーティーに少し遅れましたが、上記の解決策は私にはうまくいきませんでした、それで私の0.02$を共有します

Mokcitoバージョン:1.10.19

MyClass.java

private int handleAction(List<String> argList, String action)

Test.java

MyClass spy = PowerMockito.spy(new MyClass());

以下は私にはうまくいきませんでした(実際のメソッドが呼び出されていました):

1.1。

doReturn(0).when(spy , "handleAction", ListUtils.EMPTY_LIST, new String());

2.2。

doReturn(0).when(spy , "handleAction", any(), anyString());

3.3。

doReturn(0).when(spy , "handleAction", null, null);

次の作業:

doReturn(0).when(spy , "handleAction", any(List.class), anyString());
于 2019-09-13T06:16:24.933 に答える