Mockito や PowerMockito を使用してクラス オブジェクトをモックすることは可能ですか?
何かのようなもの:
Class<Runnable> mockRunnableClass = mock(Class<Runnable>.class);
Class をモックする代わりに、代わりに Factory を使用することもできます。リファクタリングについて懸念されていることは承知していますが、これはクラスのパブリック API を変更せずに行うことができます。テストしようとしているクラスを理解するためのコードはあまり提供していませんが、API を変更せずにリファクタリングする例を次に示します。これは些細なクラスですが、アイデアが得られるかもしれません。
public class Instantiator {
public Runnable getNewInstance(Class<Runnable> runnableClass) throws Exception {
return runnableClass.newInstance();
}
}
もちろん、この簡単なクラスをテストする最も簡単な方法は、本物の Runnable クラスを使用することですが、クラスをモックしようとすると、問題が発生します。したがって、次のようにリファクタリングできます。
public class PassThruFactory {
public Object newInstance(Class<?> clazz) throws Exception {
return clazz.newInstance();
}
}
public class Instantiator {
private PassThruFactory factory = new PassThruFactory();
public Runnable getNewInstance(Class<Runnable> runnableClass) throws Exception {
return (Runnable)factory.newInstance(runnableClass);
}
}
現在、Instantiator は、以前と同じパブリック API を使用して行っていた (自明な単純な) ことを正確に行い、クラスのクライアントが独自の特別な注入を行う必要はありません。ただし、ファクトリ クラスをモックして注入したい場合は、非常に簡単に実行できます。
@jhericsが言及したように、コードをリファクタリングできない場合、エージェントを使用しない理由は多くありません。Javaシステムクラスはブートストラップクラスローダーによってロードされ、powermockはバイトコードを再定義できません。
ただし、Powermock は、システム クラスのモックを許可するエージェントと通信するようになりました。完全な説明については、こちらをご覧ください。
主なアイデアは、Javaコマンドを変更して追加することです:
-javaagent: path/to/powermock-module-javaagent-1.4.12.jar
このエージェントが行っている基本的なことは、特定のテストで将来のモックを可能にするために、クラスを定義解除することです。そのため、JUnit などのエージェントと通信するには、特定の型を使用する必要があります。
@Rule PowerMockRule rule = new PowerMockRule(); // found in the junit4 rule agent jar
TestNG もサポートされています。詳細については、 wikiページを確認してください。
それが役立つことを願っています。
まず、コメントに記載されているように、次のことを行う必要があります。
Class<Runnable> mockRunnableaClass = (Class<Runnable>)mock(Class.class);
ただし、PowerMockの制限により、通常の方法では機能しません。クラスはJavaのブートストラップクラスローダーによってロードされ、PowerMockのクラスローダーによってバイトコード操作できないため、java.lang、java.net、java.io、またはその他のシステムクラスからクラスを単純にモックインすることはできません。(PowerMock FAQ#4を参照してください。)PowerMock 1.2.5以降、これを回避できます。テストしたいクラスがこれだった場合:
public class ClassToTest {
private Class<Runnable> runnableClass;
public void setRunnableClass(Class<Runnable> runnableClass) {
this.runnableClass = runnableClass;
}
public Runnable foo() {
return runnableClass.newInstance();
}
}
次に、これを行います。
@RunWith(PowerMockRunner.class)
@PrepareForTest({ ClassToTest.class }) // Prepare the calling class for test
public class SystemClassUserTest {
@Test
public void testFoo() throws Exception {
Class<Runnable> mockClass = (Class<Runnable>) mock(Class.class);
Runnable mockRunnable = mock(Runnable.class);
ClassToTest objectUT = new ClassToTest();
objectUT.setRunnableClass(mockClass);
when(mockClass.newInstance()).thenReturn(mockRunnable);
assertThat(objectUT.foo(), is(sameInstance(mockRunnable);
}
}
これはどう。クラス PCService にオブジェクト (MS) を持つ get メソッドを作成し、それをモックします。
public class PCService implements PCServiceIf {
public MSIf getMS() {
return ms;
}
private MSIf ms = new MS();
public boolean isMovieAccessibleToMyLevel(String myLevel, String movieId) {
return getMS().getPCL(movieId);
}
}
@Test
public void testIsMovieAccessibleToMyLevelMock() {
msMock = mock(MS.class);
spy = spy(new PCService());
doReturn(msMock).when(spy).getMS();
when(msMock.getPCL(movieId)).thenReturn(value);
when(spy.getMS().getPCL(movieId)).thenReturn(value);
assertTrue(spy.isMovieAccessibleToMyLevel("PG", movieId) == true);
}