何が起こっていますか
OK、モックでメソッドをスタブするために、ここですべてを行っています。
NumberFormat
抽象クラスです。Mockito は通常のクラスと同じように抽象クラスをモックできるため、これは通常は問題ありません。問題は、メソッドの実装に関係していますNumberFormat#format(long)
。
Oracle jdk 1.7.0 update 2 を使用している実装のソース コードを見ると、このメソッドが何をするかがわかります。
public final String format(long number) {
return format(number, new StringBuffer(), DontCareFieldPosition.INSTANCE).toString();
}
NumberFormat#format(long, StringBuffer, FieldPosition)
あなたが嘲笑しているフォーマットメソッドは、実際には同じ抽象クラスにある別のフォーマットメソッドを呼び出しています。次に、そのtoString()
呼び出しの結果の結果を呼び出した結果を返します。これは、Mockito がスタブできないFINALメソッドです。
when-then 構文を使用してメソッドをスタブすると、Mockito はスタブしているメソッドを実際に呼び出します (最終的な実装がある場合)。だからあなたが書くとき:
when(formatterFake.format(1))
実際にformat
は、抽象NumberFormat
クラスに実装されたメソッドの最初のオーバーロードを呼び出しています。
の 1 番目のオーバーロードの最終的な実装は、2 番目のメソッドをformat
呼び出します。format
その 2 番目format
は の抽象メソッドですNumberFormat
。したがって、呼び出す実装はありません。
問題ありません。モックを使用しています。Mockito は、モック内の未実装のメソッドごとにデフォルトのスタブを提供します。 デフォルトでは、値を返すすべてのメソッドに対して、モックは null、空のコレクション、または適切なプリミティブ/プリミティブ ラッパー値を返します (例: int/Integer、boolean/Boolean の場合は 0、false、...)。
したがって、 への呼び出しをスタブしようとすると、実装があるため、を返すNumberFormat#format(long)
デフォルトのスタブを呼び出すことになり、それが-ed になり、そこに原因の NPE があります。NumberFormat#format(long, StringBuffer, FieldPosition)
null
.toString()
ソリューション
通常、クラスを直接モックするのではなく、インターフェイスをモックします。これにより、最終的なものがないため、この種の問題の可能性を完全に回避できます。ただし、ここではモックに使用できるインターフェイスがないため、オプションではありません。
format の 3 引数のオーバーロードを直接モックできます。これにより、必要に応じて format の引数が 1 つのバージョンを呼び出すことができるようになります。
@Test
public void test() {
final NumberFormat mockFormatter = mock(NumberFormat.class);
final StringBuffer buffer = new StringBuffer("1");
when(mockFormatter.format(anyLong(), any(StringBuffer.class), any(FieldPosition.class))).thenReturn(buffer);
System.out.println("Result: " + mockFormatter.format(1));
}
ただし、これが最善の解決策であるかどうかはわかりません。たぶん、他の誰かが体重を量るでしょう。
編集:
Garrett Hall の回答を見た後、実装について話しているときは最終的な実装を意味していることをより明確にしました。
彼が示唆するように、PowerMock では、最終的なフォーマット メソッドを直接モックすることができます。