1. ホーム
  2. unit-testing

[解決済み] mockitoのwhen()呼び出しはどのように動作するのですか?

2022-03-05 02:13:55

質問

次のようなMockitoの文があるとする。

when(mock.method()).thenReturn(someValue);

mock.method()ステートメントがwhen()に戻り値を渡すとすると、Mockitoはどのようにしてモックのプロキシを作成するのでしょうか?CGLibのようなものを使っていると想像していますが、技術的にどのように行われているのか知りたいです。

どのように解決するのですか?

簡単に言うと、あなたの例の場合、結果は mock.method() mockito では、プロキシ、メソッドのインターセプト、および MockingProgress クラスは、モック上のメソッドの呼び出しがスタブなのか既存のスタブ動作の再生なのかを判断するために、モックされたメソッドの戻り値でスタブに関する情報を渡すのではなく、モック上のメソッドの呼び出しがスタブなのか既存のスタブなのかを判断します。

mockitoのコードを見て、数分でできるミニ解析は以下の通りです。 これは非常に大雑把な説明で、ここには多くの詳細があります。 私は、あなたがチェックアウトすることをお勧めします。 ソースはgithubにあります。 をご覧ください。

まず、クラスをモック化する際に mock メソッドの Mockito クラスでは、基本的にこのようなことが起こります。

  1. Mockito.mock に委ねる。 org.mockito.internal.MockitoCore .mock のデフォルトのモック設定をパラメータとして渡します。
  2. MockitoCore.mock をデリゲートします。 org.mockito.internal.util.MockUtil .createMock
  3. MockUtil クラスは ClassPathLoader クラスのインスタンスを取得します。 MockMaker を使用して、モックを作成します。 デフォルトでは CgLibMockMaker クラスが使用されます。
  4. CgLibMockMaker は、JMockから借用したクラスを使用しています。 ClassImposterizer は、モックの作成を処理するものです。 使用されている「モッキート・マジック」の主要な部分は MethodInterceptor は、モックを作成するために使用されるモッキート MethodInterceptorFilter のインスタンスを含む MockHandler インスタンスの連鎖を作成します。 MockHandlerImpl . メソッドインターセプターは MockHandlerImpl インスタンスに呼び出しを渡し、モック上でメソッドが呼び出されたときに適用されるべきビジネスロジックを実装します (すなわち、回答がすでに記録されているかどうかを検索する、呼び出しが新しいスタブを表しているかどうかを判断するなど)。 デフォルトでは、呼び出されたメソッドに対応するスタブがまだ登録されていない場合は、 型にあわせた の値が返される。

では、例のコードを見てみましょう。

when(mock.method()).thenReturn(someValue)

以下は、このコードが実行される順番です。

  1. mock.method()
  2. when(<result of step 1>)
  3. <result of step 2>.thenReturn

何が起こっているかを理解する鍵は、モック上のメソッドが呼び出されたときに何が起こるかです。メソッドインターセプターは、メソッドの呼び出しに関する情報を渡され、そのチェーンにデリゲートされるのです。 MockHandler インスタンスに委譲され、最終的に MockHandlerImpl#handle . この間 MockHandlerImpl#handle のインスタンスを作成します。 OngoingStubbingImpl に渡し、それを共有の MockingProgress インスタンスを作成します。

このとき when メソッドが起動された後に method() に委譲されます。 MockitoCore.when を呼び出します。 stub() メソッドと同じです。 このメソッドは、進行中のスタブを共有の MockingProgress インスタンスで、モックされた method() に書き込んで、それを返します。 次に thenReturn メソッドが呼び出されます。 OngoingStubbing のインスタンスを作成します。