org.hamcrest.BaseMatcherを拡張してassertThat()で使う

Junit4.4からデフォルトで含まれるようになったorg.hamcrestパッケージ。assertThat()でテストを書いていると、デフォルトで含まれるcoreパッケージだけでは物足りない。hamcrest-libraryを追加すればバリエーションが増えるらしい(2007-10-08 - marsのメモ)。ただ、hamcrest-libraryの配布元が見つからないので、BaseMatcherを拡張して新しいMatcherを作ってみた。

数値がある値のある誤差内に収まっていることのテストを行うMatcher
  • org.hamcrest.BaseMatcher を継承して matches(Object obj) と describeTo(Description description) を実装。
  • matches(Object obj)にはマッチング処理を記述
  • describeTo(Description description)でマッチング失敗時のメッセージを作る。
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.BaseMatcher;

public class CloseTo<T> extends BaseMatcher<T> {

    private Number thisNumber;
    private Number error;

    public static <E> Matcher<E> closeTo(double number, double error) {
        return new CloseTo<E>(number, error);
    }

    public CloseTo(Number number, Number error) {
        this.thisNumber = number;
        this.error = error;
    }

    public boolean matches(Object obj) {
        if ( ! (obj instanceof Number)) {
            return false;
        }
        Number thatNumber = (Number)obj;
        double thisValue = thisNumber.doubleValue();
        double errorValue = error.doubleValue();
        double thatValue = thatNumber.doubleValue();
        return (thatValue >  thisValue - errorValue) 
                && (thatValue < thisValue + errorValue);
    }

    public void describeTo(Description description) {
        double v = thisNumber.doubleValue();
        double e = error.doubleValue();

        description.appendText("between ");
        description.appendValue(v - e);
        description.appendText(" and ");
        description.appendValue(v + e);
    }
}
こんな風にテストをかける
assertThat(r0.time, CloseTo.closeTo(9000, 50));

static importすれば頭の「CloseTo.」はとれる。

テストに失敗したときのメッセージ
java.lang.AssertionError: 
Expected: between <8950.0> and <9050.0>
     got: <1000L>