Enumの謎
列挙型のクラスに対する JUnit テストを行った際、ソースコードを全網羅しているにも関わらず、カバレッジが 100% にならないことがあります。なぜでしょう?
public enum Answer {
YES,
NO;
public Answer opposite() {
return this == YES ? NO : YES;
}
}
public class AnswerTest {
@Test
public void testOpposite() {
assertThat(Answer.YES.opposite(), theInstance(Answer.NO));
assertThat(Answer.NO.opposite(), theInstance(Answer.YES));
}
}
#答え
Answer#values() と Answer#valueOf(String) に対するテストコードが無いためでした。これらを追加することで、カバレッジが 100% になります。
public class AnswerTest {
@Test
public void testOpposite() {
assertThat(Answer.YES.opposite(), theInstance(Answer.NO));
assertThat(Answer.NO.opposite(), theInstance(Answer.YES));
}
// 追加
@Test
public void testValues() {
assertThat(Answer.values(), is(new Answer[] { Answer.YES, Answer.NO }));
}
// 追加
@Test
public void testValueOf() {
assertThat(Answer.valueOf("YES"), theInstance(Answer.YES));
assertThat(Answer.valueOf("NO"), theInstance(Answer.NO));
}
}
#解説
列挙型には次の2つのメソッドが暗黙的に定義されており、コンパイラにより自動で生成されます。
- public static E[] values()
- public static E valueOf(String name)
多くのカバレッジレポートは、ソースコードではなくバイトコードに対するカバレッジを測定するものですので、このような振る舞いになったのですね。
#四方山話
ある程度の大きさのプロジェクトになると、「単体テストでは C1 カバレッジ 100% を目標とする!」「100% に満たない場合はその妥当性をレビュアが確認する!!」なんていうテスト計画が立てられちゃったりします。
values() と valueOf(String) は自動生成されるものなのでテストする必要なんてもちろん無いわけですが、「カバレッジ 100% になってないけどどうなってるの?!」なんて聞いてくる "品質保証担当者" に説明するのとテストしちゃうのと、どっちが楽かという話ですね...
・・・
本稿は、以前の投稿 のソースコードからのスピンオフ記事になります。Color クラスなどのテストコードを書いていて気づいたので投稿しました。
よろしければこちらの投稿も見てやってちょ → 「リバーシで遊んで覚える Java 8.」
なお nmby の流儀は、test first ならぬ test later です。。。
・・・
本稿の内容は初歩的なものでした。
Qiita の投稿に難易度フラグ(初歩~高度)なんかがあると、便利かもしれませんね。