前提
2018/2/17時点のstable版 junit-quickcheck v0.7を元に書いてます。
概要
「プロパティ」というのは、特定の入力が与えられたら、特定の出力を返しますよというコードの特徴のことを言うそうです。例えば、素因数分解するコードを想定すると、2以上の数と、その素因数分解した数のリストを全てかけ合わせたものは一致するという特徴=「プロパティ」があります。
(例)n = 36のとき、素因数分解した結果は、2, 2, 3, 3、掛け合わせると、2 x 2 x 3 x 3 = 36となり、元のnと一致します。
このプロパティを使ったテストについて、全ての入力値nについてテストするのは現実的ではないので、junit-quickcheckではランダムに入力値nを生成して、テストを実施することが可能です。
HaskellのQuickcheckにインスパイアされて作られたそうです。
素因数分解のコード例
@RunWith(JUnitQuickcheck.class)
public class PrimeFactorsProperties {
// 2 - Integer.MAX_VALUEまでの範囲で入力値nを生成する(デフォルト100個)
@Property
public void factorsMultiplyToOriginal(@InRange(min = "2", max = "2147483647") BigInteger n) {
// 入力値nは1より大きい
assumeThat(n, greaterThan(BigInteger.valueOf(1)));
// 素因数分解した結果を掛け合わせる
BigInteger product = ONE;
for (BigInteger each : PrimeFactors.of(n))
product = product.multiply(each);
// 元のnと、素因数分解の結果を掛け合わせたものは一致する
System.out.println("n = " + n);
assertEquals(n, product);
}
}
出力
n = 529647233
n = 1429992675
n = 1879932678
n = 1507927300
n = 1812653008
n = 393176714
n = 368739357
n = 1728382176
n = 607948744
n = 601709453
n = 1993428603
機能
サポートされる型
上記の例では、BigInteger型に対して入力値を自動生成しています。Date、enum、Stringなどもサポートされます。
Generatorを定義することで、自分で作ったクラスも利用可能です。
自動生成される値のカスタマイズ
上記の例では、@InRangeで生成される値の範囲を設定しています。
@When(satisfies = "#_ >= 0 && #_ <= 9") int digit) {
のようにOGNLで設定することも可能です。
自動生成される値の数
デフォルトでは100個の値を生成しますが、trials属性を設定することで変更可能です。
@Property(trials = 250) public void northernHemisphere(
自動生成シード
デフォルトではJUnitテスト実行の度に違う入力データを生成しますが、シードを与えることで、何回実行しても同じ入力データを生成するようになります。
@Property public void holds(@When(seed = -1L) int i) {
結論
プロパティベースのテストは、従来のテストを補完する位置づけなのかなと思います。そういう意味では、より品質を高めるための手段として利用できるのではないでしょうか。
参考資料
- pholser/junit-quickcheck: Property-based testing, JUnit-style
- v0.7 document
- v0.7 documentのサンプルコードを一通り実装してみた
- QuickCheck: An Automatic Testing Tool for Haskell