JMockitを利用したテストの失敗時に「mockit.internal.MissingInvocation」というエラーが発生することがある。 以下のスタックトレースでは「Missing 1 invocation」というメッセージが表示されている。 これは、モックしたメソッドが指定回数呼ばれなかったことを意味する。テスト結果だけなく、モックが正常に使われているかまで厳密にチェックしているためである。
mockit.internal.MissingInvocation: Missing 1 invocation to:
mockittest2.MyCalendar#getToday()
on mock instance: mockittest2.MyCalendar@7786df0f
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: Missing invocations
at mockittest2.MyCalendar.getToday(MyCalendar.java)
at mockittest2.MockitTest$1.(MockitTest.java:19)
at mockittest2.MockitTest.testIsDecember(MockitTest.java:18)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.lang.reflect.Method.invoke(Method.java:597)
... 6 more
このエラーが発生した直接的な原因として考えられるのは、「モックの設定が正しくない」「プログラムが想定通り動いていない」のどちらかである。 よって、モックメソッドの呼ばれる回数を適切に修正するか、プログラムを正しく修正することなどで対応することができる。
なおモックのメソッドが呼ばれる回数を厳密にチェックさせたくない場合は「Expectations」ではなく「NonStrictExpectations」を使えばよい。 NonStrictExpectationsは厳密なチェックを実施しない。
以下にサンプルプログラムを示す。詳細な説明は省くが、MockitTestのNonStrictExpectations内でMyCalendar#getToday()を設定しているが、実際のテスト対象クラスでgetToday()は呼ばれない。 Expectationsの場合、この状態でテストするとMissingInvocationが発生するが、NonStrictExpectationsにすれば例外は発生しない。
package mockittest2;
import static org.junit.Assert.*;
import org.junit.Test;
import mockit.NonStrictExpectations;
import mockit.Mocked;
public class MockitTest {
@Mocked
private MyCalendar myCal;
@Test
public void testIsDecember() {
// ExpectationsからNonStrictExpectationsに変える
new NonStrictExpectations() {{
myCal.getToday();
result = "2015/05/01";
}};
Sample sample = new Sample();
assertFalse(sample.isDecember(null));
}
}
Sample.java
package mockittest2;
public class Sample {
/** 現在日が12月か判定 */
public boolean isDecember(MyCalendar myCal) {
// nullの場合はfalseを返却
if(myCal == null){
return false;
}
String month = myCal.getToday().split("/")[1];
if("12".equals(month)){
return true;
}
return false;
}
}
MyCalendar.java
package mockittest2;
import java.text.SimpleDateFormat;
import java.util.Calendar;
public class MyCalendar {
public String getToday() {
Calendar cal = Calendar.getInstance();
return new SimpleDateFormat("yyyy/MM/dd").format((cal.getTime()));
}
}