テストするクラスで作成/初期化されていない、静的ではない(シングルトンパターン)、またはフックするための何らかのテストコンストラクターがない場合に、実行時にモックオブジェクトを取得するにはどうすればよいですか?
ユニットテストを記述しているクラスで、まだ遭遇/解決していないシナリオに遭遇しました。私がテストしているクラスのプライベート変数であるJMSリソース(参照用にQueueConnectionFactory
ですが、重要ではありません)があります。 _javax.annotation.Resource
_アノテーションが付いているため、実行時に使用可能であると見なされます。テスト中はそうではないため、このオブジェクトをモックする必要が生じます。
それは静的クラスではなく、静的な方法で使用されていません。もしそれが実行されたさまざまな静的モッキングメソッドを使用して簡単にモックできた場合。リソースがローカルで(コンストラクター内またはテストコンストラクター内でさえ)作成されることはないので、テストの実行時に実際のオブジェクトの代わりにモックが使用されるようにMockオブジェクトを渡す方法はありません。このリソースをモックしてテストを実行すると、テストしているクラスのプライベート_@Resource
_オブジェクトの代わりに使用されるようにするにはどうすればよいですか?
参考までに、ファクトリが初期化/モックされていないため、コードはQueueConnectionFactory
でcreateConnection()
を呼び出しており、nullポインタ例外をスローしています。
_@Stateless
public class Example{
@Resource(name = "jms/exampleQCF")
private QueueConnectionFactory queueFactory;
...
public void testMe(){
Connection connection = queueFactory.createConnection();
...
}
}
_
Mockito/Powermockが提供しなければならないすべてのオプションを探し回り、解決策を見つけました(他の人がこの同じ問題に遭遇した場合に備えて解決策を見つけます)。
初期化されていない(他の場所で作成されたと想定される)プライベートメンバー変数がある場合、_@InjectMocks
_アノテーションを使用して、テストするクラスに必要なモックを「挿入」できます。
@InjectMocks
_(org.Mockito.InjectMocks)を付けます。@Mock
_アノテーションを使用して、注入するモックをセットアップします。 @Mock (name = "privateVariableNameHere")
nameプロパティを使用して、Mockオブジェクトをテストするクラス内のプライベート変数にマップします。@Before
_アノテーション付きの「セットアップ」メソッドを使用することです。次に、その内部でMockitoAnnotations.initMocks(this);
を呼び出して、_@Mock
_アノテーションで何かをすばやく初期化します。@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();
}
}
_
ここにいくつかのアプローチ:
ReflectionTestUtils
:ReflectionTestUtils.setField(objectToTest, "privateFieldName", mockObjectToInject);
。これにより、別の依存関係を導入する必要がなくなります。org.mockito.internal.util.reflection.FieldSetter
_。PowerMock.Whitebox.setInternalState()
プライベートフィールドをモックします。内部ローカル変数の作成をモックする必要がある場合は、PowerMockito.whenNew(Foo.class).withNoArguments()。thenReturn(foo); `を使用します。とても、とても便利です。同じことをする他の方法が見つかりません。
Mockitoだけでは、when(any(Foo.class)
が機能しないため、ローカル変数の作成をモックできません。 nullを返します。コンパイルはできますが動作しません。