コードのどこかでメソッドを変更したため、テストが異常に失敗することはありませんでしたが、JMock はそうではないと考えているようです。
この問題を最小限の粗雑さまで煮詰めました。これは次のようになります。
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.lib.legacy.ClassImposteriser;
import org.junit.Test;
public class TestMocking {
@Test
public void test() {
Mockery mockery = new Mockery() {{
setImposteriser(ClassImposteriser.INSTANCE);
}};
final Owner owner = mockery.mock(Owner.class);
final RealThing thing = mockery.mock(RealThing.class, "thing");
mockery.checking(new Expectations() {{
oneOf(owner).getThing(); will(returnValue(thing));
oneOf(thing).method(); will(returnValue(Collections.emptyList()));
}});
owner.getThing().method();
mockery.assertIsSatisfied();
}
public static interface Owner {
BaseThing getThing();
}
public static interface BaseThing {
Collection<?> method();
}
public static interface RealThing extends BaseThing {
List<?> method();
}
}
(編集:これは、クラスがなくなっても ClassImposteriser を使用するようになりました。これは、その imposteriser なしでまったく同じコードを実行でき、テストに合格することを実証したかったためです。)
これを実行した結果:
unexpected invocation: thing.method()
expectations:
expected once, already invoked 1 time: owner.getThing(); returns <thing>
expected once, never invoked: thing.method(); returns <[]>
what happened before this:
owner.getThing()
つまり、予期されたthing.method()が呼び出されなかったときの「予期しない」thing.method()です。これは、マルチスレッド クラスがモック オブジェクトに対してテストされているときに発生することを以前に確認しましたが、今回はすべて単一のスレッドで発生しています。私はそのようなオブジェクトをモックしなかったにもかかわらず、JMock が最初のメソッド呼び出しから何らかの形で別のモック オブジェクトを返しているようです。
より具体的な型を返すオーバーライドされたメソッドを削除すると、それはなくなりますが、明らかにそれはできません。同様に、ClassImposteriser の使用を取り除けば問題は解決しますが、実際のテストでモックしているオブジェクトの 1 つは他の人のクラスです。1 回のテストで 2 つの Mockery インスタンスを使用できると思いますが、それ以外はアイデアがありません。