次のコードがあるとします。
LinkedList list = mock(LinkedList.class);
doCallRealMethod().when(list).clear();
list.clear();
このテストを実行すると、LinkedList#clear の最初の行から NullPointerException がスローされます。
public void clear() {
Entry<E> e = header.next;
while (e != header) {
Entry<E> next = e.next;
//Code omitted.
ただし、ヘッダーは以前にインスタンス化されています:
private transient Entry<E> header = new Entry<E>(null, null, null);
誰かがモックの作成中に何が起こっているのか説明してもらえますか?
####### アップデート。######
すべての回答、特に Ajay の回答を読んだ後、Objenesis のソース コードを調べたところ、Reflection API を使用して (CGLIB を介して) プロキシ インスタンスを作成しているため、階層内のすべてのコンストラクターが java.lang.Object までバイパスされていることがわかりました。
この問題をシミュレートするサンプル コードは次のとおりです。
public class ReflectionConstructorTest {
@Test
public void testAgain() {
try {
//java.lang.Object default constructor
Constructor javaLangObjectConstructor = Object.class
.getConstructor((Class[]) null);
Constructor mungedConstructor = ReflectionFactory
.getReflectionFactory()
.newConstructorForSerialization(CustomClient.class, javaLangObjectConstructor);
mungedConstructor.setAccessible(true);
//Creates new client instance without calling its constructor
//Thus "name" is not initialized.
Object client = mungedConstructor.newInstance((Object[]) null);
//this will print "CustomClient"
System.out.println(client.getClass());
//this will print "CustomClient: null". name is null.
System.out.println(client.toString());
} catch(Exception e) {
e.printStackTrace();
}
}
}
class CustomClient {
private String name;
CustomClient() {
System.out.println(this.getClass().getSimpleName() + " - Constructor");
this.name = "My Name";
}
@Override
public String toString() {
return this.getClass().getSimpleName() + ": " + name;
}
}