技術空間

JMockit

MissingInvocationの原因とNonStrictExpectations


TOP > JMockit > MissingInvocationの原因とNonStrictExpectations



■MissingInvocationの原因

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にすれば例外は発生しない。

MockitTest.java
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()));
    }
}


TOP > JMockit

Tweet ̃Gg[͂ĂȃubN}[Nɒlj
技術空間