7

StackOverflow に関する私の最初の質問。次のようなことができるようになりたいです。

SomeClass モック = モック (SomeClass.class);

String methodName = "someMethod"; OR メソッド method = ...someMethod...

これらの両方 (モックとメソッド) を組み合わせて、次のことを行います。

when(mock.someMethod()).thenReturn(null);

もちろん、「null」値は私のニーズに応じて変更されますが、次の 2 つのことを決定しようとしています。

1) Javaで このようなことをすることさえ可能ですか?これは、クラス オブジェクトとメソッドを methodCall に結合することです。

2) どうすればそのようなことを行うことができますか?

私はこれを際限なく研究しましたが、何も見つかりません。問題は、これが通常のクラスと通常のメソッド (someClass と someMethod が一緒になって someClass.someMethod() を実行する) で機能する場合でも、これは when(内で使用するためのモック オブジェクトで機能する必要があることに注意してください。 ) 電話。

回答: when(method.invoke(mock)).thenReturn("Hello world."); は正しい構文であり、リフレクションは実際に when() 呼び出し内で機能します。ありがとうケビン・ウェルカー!

4

2 に答える 2

7

あなたは基本的に、あなたの応答によって変更された私のコメントを回答として再投稿するように私に依頼したので、ここにそれがあります:

次のようにリフレクションを使用してみてください。

when(method.invoke(mock)).thenReturn("Hello world.");

ただし、クラスをモック/スパイできないためMethod(これは最終的なものです)、これがどのように機能するかはわかりません。Mockitowhen()は、モックまたはスパイでのみ機能します。これが本当にうまくいっている場合は、もう少し詳細を投稿できますか?

それが機能しない場合は、OP のコメントで提案したように、CGLib ルートに移動して Mockito をバイパスできます。一見するとそれほど難しいものではありません。私の OSS プロジェクトFuncito (モッキング フレームワークではありません) では、Mockito CGLib プロキシ コードの多くを削除し、必要に応じて書き直しました。クラスのプロキシ化とメソッド呼び出しのインターセプトの世界をより簡単に理解できます。

コメント への追加の返信 これがどのように機能しているかはわかりますが、どのように機能しているかを本当に理解しているかどうかはわかりません。これが問題になる理由は、Mockito 自体の動作方法が今後変更されると、ソリューションが壊れてしまう可能性があるためです。本質的に、それが機能する理由はほとんど偶然ですが、確かに機能します。

動作するはずの方法when()は、括弧の間で発生するのは、クラスの実際のインスタンスではなく、クラスの単なるファンシープロキシである、以前に作成された Mockito 生成のモックまたはスパイに対するメソッド呼び出しです。プロキシには、偽のプロキシ メソッド呼び出しをインターセプトし、基本的にそれを登録済みのプロキシ メソッド呼び出しのリストに追加する特別なロジックがあります (これはIOngoingStubbing、後で使用するために、またはそのようなものと呼ばれるものに格納されます)。when()Java はメソッドを呼び出す前にパラメーターを評価するため、メソッドが実際に実行される前に、プロキシされたメソッド呼び出しが登録/記憶されることが保証されます。がwhen()行うことは、この IOngoingStubbing から取り出され、thenReturns()呼び出されるオブジェクトになります。

これを「正しく」使用していませんが、それでも機能します。どのように?IOngoingStubbing必要なのは、実行前に登録するためにプロキシ上のメソッドを呼び出す必要があることだけwhen()です。プロキシのメソッドを直接呼び出しているのではなく、プロキシを に渡すことで、プロキシのメソッドを間接的に呼び出していますMethod.invoke()。したがって、基準が満たされ、when()すでにプロキシ メソッド呼び出しが に登録されていIOngoingStubbingます。

次のコードでも同じような「偶発的な」幸せを見ることができます。

@Test
public void testSomething() throws Exception {
    List listMock = mock(List.class);
    Method m = List.class.getDeclaredMethod("get", int.class);
    m.invoke(listMock, Mockito.anyInt());

    when(null).thenReturn("Hello World");  // Huh? passing null?

    assertEquals("Hello World", listMock.get(0)); // works!
}

上記のテストは実際にパスします。への引数が null であっても、ステートメントが呼び出されるwhen前に、プロキシ (つまり、モック) インスタンスに正しいメソッドが呼び出されていることが重要です。when

Mockito が内部での基本的な動作を変更する可能性は低いですが、将来的にこれが壊れる可能性はまだあります。私が言ったように、それが機能することは多かれ少なかれ幸運な偶然です. その仕組みとそれに伴うリスクを理解している限り、より大きな力を発揮できます。

于 2012-04-12T21:09:21.400 に答える
0

クラスの初期化後に新しいメソッドを追加することは、Mockito に提供されているインターフェイスまたはクラスでメソッドが指定されていない限り、できないと思います。初期化後にクラス署名を変更することはできませんが、これは不可能です。

スタブ メソッドの呼び出しについては、http ://code.google.com/p/mockito/ を参照してください。スタブ メソッド呼び出しのサンプルがあります。

静的な回答ではなく、動的な回答を得たい場合は、Mockito を使用しないでください。偽のオブジェクトまたはスタブを使用して、テスト用の動作を取得します。この問題の詳細については、 http : //martinfowler.com/articles/mocksArentStubs.htmlを参照してください。

于 2012-04-12T13:29:43.480 に答える