私は次のクラスを持っています:
public class MyClass {
private Apple apple;
public void myMethod() {
Apple = AppleFactory.createInstance(someStringVariable);
....
....
....
}
}
そしてTestクラス:
@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
@InjectMocks
MyClass myClass;
@Test
public void myMethod(){
...
...
...
}
}
MyClassのモックとしてAppleインスタンスを注入するにはどうすればよいですか?
これを解決するには3つの方法があります。
Abstract factory:静的メソッドを使用する代わりに、具象ファクトリクラスを使用します。
public abstract class AppleFactory {
public Apple createInstance(final String str);
}
public class AppleFactoryImpl implements AppleFactory {
public Apple createInstance(final String str) { // Implementation }
}
テストクラスで、ファクトリーをモックします。
@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
@Mock
private AppleFactory appleFactoryMock;
@Mock
private Apple appleMock;
@InjectMocks
MyClass myClass;
@Before
public void setup() {
when(appleFactoryMock.createInstance(Matchers.anyString()).thenReturn(appleMock);
}
@Test
public void myMethod(){
...
...
...
}
}
PowerMock:静的メソッドのモックを作成するには、PowerMockを使用します。 関連する質問に対する私の回答 を見て、それがどのように行われるかを確認してください。
テスト可能なクラス:Apple
の作成をprotected
メソッドでラップし、それをオーバーライドするテストクラスを作成します。
public class MyClass {
private Apple apple;
public void myMethod() {
Apple = createApple();
....
....
....
}
protected Apple createApple() {
return AppleFactory.createInstance(someStringVariable);
}
}
@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
@Mock
private Apple appleMock;
@InjectMocks
MyClass myClass;
@Test
public void myMethod(){
...
...
...
}
private class TestableMyClass extends MyClass {
@Override
public void createApple() {
return appleMock;
}
}
}
もちろん、テストクラスではTestableMyClass
ではなくMyClass
をテストする必要があります。
それぞれの方法について私の意見をお話しします。
抽象ファクトリメソッドが最適です-これは、実装の詳細を隠す明確な設計です
テスト可能なクラス-最小限の変更を必要とする2番目のオプションです
PowerMock
オプションは私の一番のお気に入りではありません-より良い設計を行う代わりに、問題を無視して隠します。しかし、それはまだ有効なオプションです。Avi&Ev0oDの最初の回答について。抽象クラスは拡張のみが可能で、実装はできません。
public abstract class AppleFactory {
public abstract Apple createInstance(final String str);
}
public class AppleFactoryImpl extends AppleFactory {
public Apple createInstance(final String str) { // Implementation }
}
Aviが提案したソリューションに加えて、4番目の可能性を選択できます。
インジェクト・ファクトリー:これは、私にとって、refacrotするコードがすでにある場合の最良のオプションです。このソリューションでは、Porductionコードを変更する必要はなく、ファクトリクラスとテストを変更するだけです。
public class AppleFactory
{
private static Apple _injectedApple;
public static createInstance(String str)
{
if (_injectedApple != null)
{
var currentApple = _injectedApple;
_injectedApple = null;
return currentApple;
}
//standard implementation
}
public static setInjectedApple(Apple apple)
{
_injectedApple = Apple;
}
}
これで、静的ファクトリーを簡単に使用できます。
@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
@Mock
private Apple appleMock;
@InjectMocks
MyClass myClass;
@Before
public void setup() {
AppleFactory.setInjectedApple(appleMock);
}
@Test
public void myMethod(){
...
...
...
}
}