使用Mockito試抽象クラス
-
23-08-2019 - |
質問
い試験抽象クラスです。だができま 手書きの模擬 を継承するクラスです。
いことを嘲笑うの枠組みを使用していMockito)の代わりに手作っ模擬?いかがですか?
解決
次の提案をみましょう、あなたは「本当の」サブクラスを作成せずに抽象クラスをテスト - モックはのあるサブクラス
。、その後に呼び出されるすべての抽象メソッドをモック、Mockito.mock(My.class, Mockito.CALLS_REAL_METHODS)
を使用します。
例:
public abstract class My {
public Result methodUnderTest() { ... }
protected abstract void methodIDontCareAbout();
}
public class MyTest {
@Test
public void shouldFailOnNullIdentifiers() {
My my = Mockito.mock(My.class, Mockito.CALLS_REAL_METHODS);
Assert.assertSomething(my.methodUnderTest());
}
}
注:このソリューションの美しさは、あなたがいる限り、彼らが呼び出されることはありませんよう、抽象メソッドを実装していないのHAVE を行うということです。
。 スパイはあなたの抽象クラスのインスタンス化サブクラスを作成する必要が意味し、インスタンスを必要とするため、私の正直な意見では、これは、スパイを使用するよりも滑らかな印象です。
他のヒント
場合にだけ試験の一部のコンクリートの方法に触れることなく任意の抄録を利用でき CALLS_REAL_METHODS
参照 Mortenの回答がの場合の具体的な手法試験に通話を録または未実装インタフェースのメソッド、これは動作しません--Mockitoまでも"できなコリメソッドをjavaインタフェース。"
(まつり"はしゃデザインが、一部の枠組み、などタペスト4のような力でお願いします。)
の回避策は逆にこのアプローチ--利用、通常の模擬挙動(すなわち、すべての英/stubbed)の利用 doCallRealMethod()
明示的に呼び出しのコンクリートの方法なければなりません。E.g.
public abstract class MyClass {
@SomeDependencyInjectionOrSomething
public abstract MyDependency getDependency();
public void myMethod() {
MyDependency dep = getDependency();
dep.doSomething();
}
}
public class MyClassTest {
@Test
public void myMethodDoesSomethingWithDependency() {
MyDependency theDependency = mock(MyDependency.class);
MyClass myInstance = mock(MyClass.class);
// can't do this with CALLS_REAL_METHODS
when(myInstance.getDependency()).thenReturn(theDependency);
doCallRealMethod().when(myInstance).myMethod();
myInstance.myMethod();
verify(theDependency, times(1)).doSomething();
}
}
更に追加:
非voidの方法できます。 thenCallRealMethod()
代わりに、例えば:
when(myInstance.myNonVoidMethod(someArgument)).thenCallRealMethod();
その他Mockitoまでも"未完のstubbing検出されます。"
あなたはスパイ(ただし1.8+ Mockitoの最新バージョンを使用)を使用することによって、これを達成することができます。
public abstract class MyAbstract {
public String concrete() {
return abstractMethod();
}
public abstract String abstractMethod();
}
public class MyAbstractImpl extends MyAbstract {
public String abstractMethod() {
return null;
}
}
// your test code below
MyAbstractImpl abstractImpl = spy(new MyAbstractImpl());
doReturn("Blah").when(abstractImpl).abstractMethod();
assertTrue("Blah".equals(abstractImpl.concrete()));
嘲笑う枠組みできるようデザインされた模擬出依存関係のクラスにいます。ご利用の際は、嘲笑う枠組みを模擬クラスは、枠組みを動的にサブクラスを作成したり、不具合を放置した場合、そのメソッド実装コードを検出するときに呼び出され、還元を偽値です。
試すときにはabstractクラスなので、実行するの抽象メソッドの下試験(SUT)で嘲笑う枠組みだと考えている。
の混乱がこの問題の答えと連と言った手工芸品、モックからのおabstractクラスです。ない電話などのクラス模擬.モッククラスとして使用されているの交換のための依存関係は、プログラムへの期待、問い合わせることができるがその期待される。
代わりにもたらされたと考えられるこれを定めるための非抽象サブクラスの抽象クラスにテストです。その結果にすぎコードすることをできるだけるクラスでは難しい。
代替的解決するにはテストケース自体の概要、要旨を作成する方法にSUT(つまり、テストケースを利用する テンプレート方法 デザインパターン).
カスタム答えを使用してみてください。
例
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
public class CustomAnswer implements Answer<Object> {
public Object answer(InvocationOnMock invocation) throws Throwable {
Answer<Object> answer = null;
if (isAbstract(invocation.getMethod().getModifiers())) {
answer = Mockito.RETURNS_DEFAULTS;
} else {
answer = Mockito.CALLS_REAL_METHODS;
}
return answer.answer(invocation);
}
}
これは、抽象メソッドのモックを返し、具体的な方法のため、実際のメソッドを呼び出します。
本当に私は抽象クラスをからかっについて悪い感じさせること(モックで不足しているスーパー())と呼ばれるもモック性質を(初期化デフォルトにMockitoでどのような方法があるように思われます)どちらもデフォルトコンストラクタYourAbstractClass(という、事実であります空のArrayListまたはLinkedListの)と例えばリストのプロパティます。
私の抽象クラスは、(基本的には、クラスのソースコードが生成されます)、リスト要素の依存セッターインジェクション、またそれが(私は手動で追加しようとした)リスト要素を初期化するコンストラクタを提供していません。
唯一のクラス属性は、デフォルトの初期化を使用します。 プライベートリストDEP1 =新しいArrayListに。 プライベートリストDEP2 =新しいのArrayList
は、実際のオブジェクトインプリメンテーション(ユニットテストクラスの例えば内部クラス定義、オーバーライド抽象メソッド)を使用して(適切なフィールドの初期化を行い)実際のオブジェクトをスパイすることなく、抽象クラスを模擬する方法がないようにします。
のみPowerMockは、さらにここに役立つだろうと残念ます。
あなたは、単にモックを作成することができ、テスト中のあなたのクラスとしてテストクラスが(異なるソース・ルートの下に)同じパッケージ内にあると仮定します:
YourClass yourObject = mock(YourClass.class);
、あなたはちょうどあなたが他の方法と同じようにテストしたいメソッドを呼び出します。
あなたはスーパーメソッドを呼び出す任意の具体的な方法に期待して呼び出された各メソッドへの期待を提供する必要があります - あなたはMockitoでそれを行うだろうかどうかはわかりませんが、私はそれはEasyMockで可能だと信じています。
。このすべてはYouClass
の具体的なインスタンスを作成し、あなたに各抽象メソッドの空の実装を提供する努力を保存してやっている。
余談として、私は多くの場合、それは私がその公開インターフェースを介してテスト実装例として役立つ私のテスト、抽象クラスを実装することが役立ちます。
あなたは、あなたのテストで匿名クラスと抽象クラスを拡張することができます。 例えば(JUnitの4を使用):
private AbstractClassName classToTest;
@Before
public void preTestSetup()
{
classToTest = new AbstractClassName() { };
}
// Test the AbstractClassName methods.
あなたのモックを注入し、匿名クラスをインスタンス化し、そのクラスをテストすることができます。
@RunWith(MockitoJUnitRunner.class)
public class ClassUnderTest_Test {
private ClassUnderTest classUnderTest;
@Mock
MyDependencyService myDependencyService;
@Before
public void setUp() throws Exception {
this.classUnderTest = getInstance();
}
private ClassUnderTest getInstance() {
return new ClassUnderTest() {
private ClassUnderTest init(
MyDependencyService myDependencyService
) {
this.myDependencyService = myDependencyService;
return this;
}
@Override
protected void myMethodToTest() {
return super.myMethodToTest();
}
}.init(myDependencyService);
}
}
視認性が抽象クラスprotected
のプロパティmyDependencyService
ためClassUnderTest
しなければならないことに留意してください。
Whitebox.invokeMethod(..)は、この場合に便利であることができる。
Mockitoは@Mock
注釈によって抽象クラスをあざけることができます:
public abstract class My {
public abstract boolean myAbstractMethod();
public void myNonAbstractMethod() {
// ...
}
}
@RunWith(MockitoJUnitRunner.class)
public class MyTest {
@Mock(answer = Answers.CALLS_REAL_METHODS)
private My my;
@Test
private void shouldPass() {
BDDMockito.given(my.myAbstractMethod()).willReturn(true);
my.myNonAbstractMethod();
// ...
}
}
欠点は、コンストラクタのパラメータが必要な場合は、それを使用することができないということです。