こんな時に
どうしてもJUnitでprivateメソッドも含めてカバレッジ100%にしたい!
(基本はpublicメソッドのテスト経由で全部通した方が自然)
例えば
以下のようなクラスで一箇所だけ自然にテストを通せないprivateメソッドがあったとする。
(中身がスカスカなのはご愛嬌)
SampleUtil.java
private String getStatus(String param, TestEntity testEntity) {
String result = null;
switch (param) {
case "1":
result = "A" + testEntity.getCode();
break;
case "2":
result = "B" + testEntity.getCode();
break;
case "3":
result = "C" + testEntity.getCode();
break;
default :
result = "Z" + testEntity.getCode(); // ← ここのカバレッジが通らない!
}
return result;
}
対応方法
Mockitoを使う
https://site.mockito.org/
準備
私の場合はSpringBootとJUnitは既に導入済みのため、
dependencyに以下を追記してMockitoのライブラリを取得する。
Maven利用の場合
pom.xml
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-all -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
Gradle利用なら
build.gradle
dependencies {
// https://mvnrepository.com/artifact/org.mockito/mockito-all
testCompile group: 'org.mockito', name: 'mockito-all', version: '1.10.19'
}
使い方
テストクラスで以下の様に書けばいい
SampleUtilTest.java
private SampleUtil sampleUtil;
private static int testId = 1; // 後の検証で使う変数
@Test
public void getStatus() {
// SampleUtil#getStatusを実行できる様に設定
Method method = SampleUtil.class.getDeclaredMethod("getStatus", String.class, TestEntity.class);
method.setAccessible(true);
// テスト用のパラメータ設定
String param = "4";
TestEntity testEntity = new TestEntity();
testEntity.setCode("001");
// テスト実行
String status = (String) method.invoke(sampleUtil, param, testEntity);
assertThat(status, is("Z001"));
}
SampleUtilのgetStatus()メソッドに対してaccessible=trueを設定することでアクセッサレベルを無視して呼び出すことが可能になる。
応用編
テスト内でprivate変数に対してgetやsetしたい場合
以下のtestIdはSampleUtil.java内でprivate定義されている変数。
ここではgetしてみる。
SampleUtilTest.java
@Test
public void getParams() {
SampleUtil sampleUtil = new SampleUtil();
assertThat(Whitebox.getInternalState(sampleUtil, "testId"), is(1));
}
この様に実装することでアクセッサレベルを無視して呼び出すことが可能。
最後に
ここで紹介した以外にもstaticメソッドを書き換えたりJUnitのテストの幅が広がる様な機能を多く備えているので、
興味のある人は突っ込んで調べてみるといいかも。