web-dev-qa-db-ja.com

存在すると想定されるプライベート変数のモック

テストするクラスで作成/初期化されていない、静的ではない(シングルトンパターン)、またはフックするための何らかのテストコンストラクターがない場合に、実行時にモックオブジェクトを取得するにはどうすればよいですか?

ユニットテストを記述しているクラスで、まだ遭遇/解決していないシナリオに遭遇しました。私がテストしているクラスのプライベート変数であるJMSリソース(参照用にQueueConnectionFactoryですが、重要ではありません)があります。 _javax.annotation.Resource_アノテーションが付いているため、実行時に使用可能であると見なされます。テスト中はそうではないため、このオブジェクトをモックする必要が生じます。

それは静的クラスではなく、静的な方法で使用されていません。もしそれが実行されたさまざまな静的モッキングメソッドを使用して簡単にモックできた場合。リソースがローカルで(コンストラクター内またはテストコンストラクター内でさえ)作成されることはないので、テストの実行時に実際のオブジェクトの代わりにモックが使用されるようにMockオブジェクトを渡す方法はありません。このリソースをモックしてテストを実行すると、テストしているクラスのプライベート_@Resource_オブジェクトの代わりに使用されるようにするにはどうすればよいですか?

参考までに、ファクトリが初期化/モックされていないため、コードはQueueConnectionFactorycreateConnection()を呼び出しており、nullポインタ例外をスローしています。

_@Stateless
public class Example{
  @Resource(name = "jms/exampleQCF")
  private QueueConnectionFactory queueFactory;

  ...

  public void testMe(){
    Connection connection = queueFactory.createConnection();
    ...
  }
}
_
19
Walls

Mockito/Powermockが提供しなければならないすべてのオプションを探し回り、解決策を見つけました(他の人がこの同じ問題に遭遇した場合に備えて解決策を見つけます)。

初期化されていない(他の場所で作成されたと想定される)プライベートメンバー変数がある場合、_@InjectMocks_アノテーションを使用して、テストするクラスに必要なモックを「挿入」できます。

  1. テストするクラスの変数をテストクラスに追加し、アノテーション_@InjectMocks_(org.Mockito.InjectMocks)を付けます。
  2. _@Mock_アノテーションを使用して、注入するモックをセットアップします。 @Mock (name = "privateVariableNameHere") nameプロパティを使用して、Mockオブジェクトをテストするクラス内のプライベート変数にマップします。
  3. セットアップ関数で、またはクラスを呼び出す前に、モックを初期化します。私が見つけた最も簡単な方法は、_@Before_アノテーション付きの「セットアップ」メソッドを使用することです。次に、その内部でMockitoAnnotations.initMocks(this);を呼び出して、_@Mock_アノテーションで何かをすばやく初期化します。
  4. テストメソッドでモック機能を定義します(テストするメソッドを呼び出す前に)。
  5. _@InjectMock_オブジェクトを使用して、テストするメソッドを呼び出します...モックは、前の手順で定義されたようにフックされ、機能する必要があります(SHOULD)。

したがって、上記で使用したサンプルクラスの場合、テスト/モックするコードは、Connectionをモックとして返し、これを使用して何でも実行できます。上記の私の質問の例に基づいて、これはコードは次のようになります。

_@RunWith(PowerMockRunner.class)
@PrepareForTest({/* Static Classes I am Mocking */})
public class ExampleTest {
  @Mock (name = "queueFactory") //same name as private var.
  QueueConnectionFactory queueFactoryMock;
  @Mock
  Connection connectionMock; //the object we want returned
  @InjectMocks
  Example exampleTester; //the class to test

  @Before
  public void setup(){
    MockitoAnnotations.initMocks(this); // initialize all the @Mock objects
    // Setup other Static Mocks
  }

  @Test
  public void testTestMe(){
    //Mock your objects like other "normally" mocked objects
    PowerMockito.when(queueFactoryMock.createConnection()).thenReturn(connectionMock);
    //...Mock ConnectionMock functionality...
    exampleTester.testMe();
  }
}
_
38
Walls

ここにいくつかのアプローチ:

  1. Spring TestingフレームワークのReflectionTestUtilsReflectionTestUtils.setField(objectToTest, "privateFieldName", mockObjectToInject);。これにより、別の依存関係を導入する必要がなくなります。
  2. _org.mockito.internal.util.reflection.FieldSetter_。
  3. PowerMock.Whitebox.setInternalState()プライベートフィールドをモックします。

内部ローカル変数の作成をモックする必要がある場合は、PowerMockito.whenNew(Foo.class).withNoArguments()。thenReturn(foo); `を使用します。とても、とても便利です。同じことをする他の方法が見つかりません。

Mockitoだけでは、when(any(Foo.class)が機能しないため、ローカル変数の作成をモックできません。 nullを返します。コンパイルはできますが動作しません。

参照: Mockito:モックプライベートフィールドの初期化

0
WesternGun