私はこれに関するいくつかの助けが必要です:
例:
_void method1{
MyObject obj1=new MyObject();
obj1.method1();
}
_
私はテストでobj1.method1()
をモックしたいのですが、透明にしたいので、コードの作成や変更はしたくありません。 Mockitoでこれを行う方法はありますか?
このコードに触れないようにするには、 Powermockito (PowerMock for Mockito)を使用できます。
これにより、他の多くのものの中でも、非常に簡単な方法で 新しいオブジェクトの作成をモックする を実行できます。
@edutesoyからの回答は、PowerMockitoのドキュメントを指しており、コンストラクターのモックをヒントとして言及していますが、質問の現在の問題にそれを適用する方法については言及していません。
これに基づいたソリューションを次に示します。質問からコードを取得する:
public class MyClass {
void method1{
MyObject obj1=new MyObject();
obj1.method1();
}
}
次のテストでは、PowerMockでインスタンス化するクラス(この例ではMyClassを呼び出しています)を準備し、PowerMockitoにMyObjectクラスのコンストラクターをスタブさせ、MyObjectインスタンスmethod1をスタブさせて、MyObjectインスタンスクラスのモックを作成します()呼び出し:
@RunWith(PowerMockRunner.class)
@PrepareForTest(MyClass.class)
public class MyClassTest {
@Test
public void testMethod1() {
MyObject myObjectMock = mock(MyObject.class);
when(myObjectMock.method1()).thenReturn(<whatever you want to return>);
PowerMockito.whenNew(MyObject.class).withNoArguments().thenReturn(myObjectMock);
MyClass objectTested = new MyClass();
objectTested.method1();
... // your assertions or verification here
}
}
それにより、内部method1()呼び出しは、必要なものを返します。
ワンライナーが好きな場合は、モックとスタブをインラインで作成してコードを短くすることができます。
MyObject myObjectMock = when(mock(MyObject.class).method1()).thenReturn(<whatever you want>).getMock();
とんでもない。いくつかの依存性注入が必要になります。つまり、obj1をインスタンス化する代わりに、何らかのファクトリによって提供する必要があります。
MyObjectFactory factory;
public void setMyObjectFactory(MyObjectFactory factory)
{
this.factory = factory;
}
void method1()
{
MyObject obj1 = factory.get();
obj1.method();
}
次に、テストは次のようになります。
@Test
public void testMethod1() throws Exception
{
MyObjectFactory factory = Mockito.mock(MyObjectFactory.class);
MyObject obj1 = Mockito.mock(MyObject.class);
Mockito.when(factory.get()).thenReturn(obj1);
// mock the method()
Mockito.when(obj1.method()).thenReturn(Boolean.FALSE);
SomeObject someObject = new SomeObject();
someObject.setMyObjectFactory(factory);
someObject.method1();
// do some assertions
}
メソッド内でFileオブジェクトの作成をモックするこの例のように、コードの変更を避け(ボリスの答えをお勧めします)、コンストラクターをモックできます。 忘れないでくださいファイルを作成するクラスを@PrepareForTest
。
package hello.easymock.constructor;
import Java.io.File;
import org.easymock.EasyMock;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
@PrepareForTest({File.class})
public class ConstructorExampleTest {
@Test
public void testMockFile() throws Exception {
// first, create a mock for File
final File fileMock = EasyMock.createMock(File.class);
EasyMock.expect(fileMock.getAbsolutePath()).andReturn("/my/fake/file/path");
EasyMock.replay(fileMock);
// then return the mocked object if the constructor is invoked
Class<?>[] parameterTypes = new Class[] { String.class };
PowerMock.expectNew(File.class, parameterTypes , EasyMock.isA(String.class)).andReturn(fileMock);
PowerMock.replay(File.class);
// try constructing a real File and check if the mock kicked in
final String mockedFilePath = new File("/real/path/for/file").getAbsolutePath();
Assert.assertEquals("/my/fake/file/path", mockedFilePath);
}
}
これを行うには、MyObjectでファクトリメソッドを作成します。
class MyObject {
public static MyObject create() {
return new MyObject();
}
}
それを PowerMock でモックします。
ただし、ローカルスコープオブジェクトのメソッドをモックすることにより、メソッドの実装のその部分に依存することになります。そのため、テストを中断せずにメソッドのその部分をリファクタリングする機能を失います。さらに、モックで戻り値をスタブ化している場合、ユニットテストは合格する可能性がありますが、実際のオブジェクトを使用するとメソッドが予期せず動作する場合があります。
要するに、あなたはおそらくこれをしようとすべきではありません。むしろ、テストでコード(TDDとも呼ばれます)を駆動させると、次のような解決策が得られます。
void method1(MyObject obj1) {
obj1.method1();
}
単体テストのために簡単にモックできる依存関係を渡します。