☕
【Java】テストケースIDをスマートに判定する
はじめに
JUnitのコードを書いていると、以下のように判定しテストケース固有のコードを書くことがある。
XxxTestCaseIdはenumとしている。その方がIDEで補完入力しやすいし、switch文(式)でも扱いやすい。
今回の手法とswitch文(式)のどちらを使うかはケースバイケースで。
// 全3ケースのうち、1ケース目と2ケース目のみ固有条件(あるいは期待値)を定義
if (testCaseId == XxxTestCaseId.XXXX_0001 || testCaseId == XxxTestCaseId.XXXX_0002) {
}
やりたいこと&実現方法
これをスマートに表現する方法を模索。
インターフェース&defaultメソッドを使って、enumの拡張を行う。
インタフェース&Utilを使っても可能だが、defaultメソッドを使った拡張のほうが読みやすい。
例えばテストケースIdが1 or 2 or 3ケース目のどれかに該当することを示すコードを書きたい場合、ユーティリティクラスを使うと以下のようになるが、
// ケース番号判定をユーティリティクラス化した例
if (TestUtil.ifNo(testCaseId, 1, 2, 3)) {
インターフェース&defaultメソッドで拡張するとこのようにスマートに書くことができる。
// enumを拡張した例
if (testCaseNo.is(1, 2, 3)) {
// 否定形も可
if (testCaseNo.isNot(1, 2, 3)) {
// 範囲指定も可
if (testCaseNo.isInRange(1).to(3)) {
コード例
以下、インターフェースの定義例。
public interface TestCaseIdEx {
String name();
/**
* テストケースIDの通番部分を数値化して取得する。
* isメソッドで通番参照するためのメソッド。
*/
default int getCaseNo() {
// 通番部分を取得(この例では下4桁)
return Integer.parseInt(name().substring(name().length() - 4));
// apache commonsのStringUtils.right(name(), 4)を使うと安全
}
default boolean is(int... no) {
if (no == null) {
return false;
}
int thisCaseNo = getCaseNo();
return Arrays.stream(no).anyMatch(n -> n == thisCaseNo);
}
default boolean isNot(int... no) {
return !is(no);
}
// 範囲指定用
// // テストケース番号3~7
// if (testCaseId.isInRange(3).to(7)) {
default TestCaseNoRange isInRange(int beginNo) {
var range = new TestCaseIdRange();
range.caseNo = getSerialNo();
range.beginNo = beginNo;
return range;
}
public class TestCaseIdRange {
private int caseNo;
private int beginNo;
boolean to(int endNo) {
return beginNo <= caseNo && caseNo <= endNo;
}
}
}
利用するときの定義。インターフェースをimplementsするだけ。
enum XxxTestCaseId implements TestCaseIdEx {
XXXX_0001,
XXXX_0002,
XXXX_0003,
…
}
Discussion