generated at
Property based testing




参考




fast-checkのdocs
ただただランダムに値を生成するのではなく、問題が起きそうな値もやや恣意的に含む
errorに対しては、Shrinkingし、人間が読みやすい報告をする



単純で自明な実装と結果を比較する
実装本体はいくらでも最適化すれば良い
例えば、 max :: [Int] -> Int のような関数を定義する際に、
自明な実装の方は max' = last . sort のように定義する
これで、ランダムに生成し、 max max' の結果が一致することを確認する
関数の等価性を使ってチェックするのかmrsekut
ts
// Properties test("biggest", () => { fc.assert( fc.property(fc.array(fc.float(), { minLength: 1 }), (n) => { return biggest(n) === modelBiggest(n); }) ); }); const biggest = (numbers: number[]) => { return numbers.reduce((acc, curr) => (acc > curr ? acc : curr), -Infinity); }; // helper const modelBiggest = (numbers: number[]) => { return numbers.sort((a, b) => a - b)[numbers.length - 1]; };
普通にExample-based testingをいくつか書き、それを汎化させてgeneratorにする
構成要素同士の不変条件を確認する
sortで、
隣り合う2つの要素を比べたときに常に後者が大きくなる
実行の前後で要素数が一致する
など
いくつかの不変条件を組み合わせないと変な実装でも常にpassしてしまう可能性があることに注意する
2つの関数が逆方向に動作する場合、それらを組み合わせて同じ結果になることを確認する
2つである必要もなく、複数の関数が円環に動作するなら使える
e.g.
encode/decode
ts
describe("properties", () => { test("synmetry", () => { fc.assert( fc.property(fc.string(), (text) => { return decode(encode(text)) === text; }) ); }); }); const encode = (text: string) => text.split("").join(","); const decode = (encoded: string) => encoded.split(",").join("");
ちなみに上記コードは "," という入力を与えたときに失敗する