最初に
PowerMockitoをプロジェクトで使っており、使い方を深く知らずに使っていたらあるところで問題が発生したので備忘録のため記述します。
問題が起こったコード
public class Main {
private String fileName;
private String extension;
public Main(String fileName, String extension){
this.fileName = fileName;
this.extension = extension;
}
public void getFileName(){
var file = new FileName(fileName);
var extension = new Extension(extension);
return file.fullName(extension);
}
}
public class FileName{
private String value;
public FileName(String value){
this.value = value;
}
public String fullName(Extension extension){
return value + extension.get();
}
}
public class Extension{
private String value;
public Extension(String value){
this.value = value;
}
public String get(){
return this.value;
}
}
上記のようなコードがあった場合、仮にExtension.get()を評価をする際ある値で返すようにしたい場合下記のようなテストコードをPowerMockitoを使って記述できます。
@RunWith(PowerMockRunner.class)
@PrepareForTest({Main.class})
public class MainTest(){
@Test
public void test01{
var mock = PowerMockito.mock(Extension.class);
PowerMockito.when(mock.get()).thenReturn(".txt");
PowerMockito.whenNew(Extension.class).withAynArguments().thenReturn(mock);
var expected = "test.txt");
var actual = new Main("test", ".exe").getFileName();
Assert.assertEquals(expected, actual);
}
}
しかし、これだと、期待値通り値が帰ってこない問題がありました。
解決方法
@PrepareForTest({Main.class})
上記を変更することで解決できました。PrepareForTestには今回の場合のようにインスタンス生成をして値を返すときにはnewを行うクラスをPrepareForTestに加えないといけないみたいです。
PrepareForTestのAPIリファレンスを読むと下記のように書いてあります
This annotation tells PowerMock to prepare certain classes for testing. Classes needed to be defined using this annotation are typically those that needs to be byte-code manipulated. This includes final classes, classes with final, private, static or native methods that should be mocked and also classes that should be return a mock object upon instantiation.
翻訳サイトを使って翻訳すると
このアノテーションはPowerMockに特定のクラスをテスト用に準備するように指示します。このアノテーションを使って定義する必要があるクラスは、一般的にバイトコード操作が必要なクラスです。これには final クラス、final、private、static、またはネイティブメソッドを持つクラスが含まれ、またインスタンス化時にモックオブジェクトを返す必要があるクラスも含まれます。
とのことです。つまり、Mockするクラスを書くのではなく、mockするクラスを呼び出しているクラスを記述しないといけないということです。