萌えハッカーニュースリーダー

2025/04/20 19:41 Falsify: Hypothesis-Inspired Shrinking for Haskell

出典: https://www.well-typed.com/blog/2023/04/falsify/
hakase
博士

やっほー、ロボ子!今日はHaskellの新しいproperty based testingライブラリ`falsify`について話すのじゃ。

roboko
ロボ子

property based testingですか。ユニットテストとは違うアプローチですね。

hakase
博士

そうそう!ユニットテストは特定の入力に対して期待される結果を検証するけど、property based testingはランダムな入力を生成して、入力と出力が特定のプロパティで関連付けられているかを検証するのじゃ。

roboko
ロボ子

なるほど。ランダムな入力を生成するんですね。それって、どんな時に役立つんですか?

hakase
博士

例えば、ソート関数がちゃんと動くかテストしたい時に、色々な長さや要素のリストを自動で生成してテストできるのじゃ。手動でテストケースを作る手間が省けるし、予期せぬバグを見つけやすくなるぞ。

roboko
ロボ子

それは便利ですね!記事によると、`falsify`はPythonの`Hypothesis`に触発されたアプローチで、monadic bindを跨いだshrinkingを実現するとのことですが、shrinkingって何ですか?

hakase
博士

shrinkingは、テストが失敗した時に、関連性の低い情報を取り除いて、デバッグを楽にする機能のことじゃ。例えば、100要素のリストでテストが失敗した時に、shrinkingによって、問題を引き起こす最小のリスト(例えば、3要素のリスト)を見つけ出すことができるのじゃ。

roboko
ロボ子

`falsify`は、最小限の反例を提供することを目指しているんですね。

hakase
博士

その通り!従来の`QuickCheck`では、generatorとshrinking functionを組み合わせていたけど、`falsify`は、生成された値をshrinkするのではなく、PRNGによって生成されたサンプルをshrinkするのじゃ。

roboko
ロボ子

PRNGですか。疑似乱数生成器ですね。

hakase
博士

`falsify`では、PRNGを分割して2つの新しいPRNGを生成する方法を提供するから、最初の値を生成せずに2番目の値を生成できるのじゃ。これは便利だぞ。

roboko
ロボ子

なるほど。`QuickCheck`の`Gen`はPRNGを入力として受け取るけど、更新されたPRNGを返さないんですね。

hakase
博士

`falsify`では、サンプルの無限ストリームではなく、サンプルの無限ツリーを提供するのじゃ。generatorは、サンプルツリーの一部を受け取り、解析し、値と更新されたサンプルツリーを生成する関数なのじゃ。

roboko
ロボ子

サンプルツリーを使うことで、何か利点があるんですか?

hakase
博士

`Hypothesis`はサンプルの線形ストリームを使用するのに対し、`falsify`は無限ツリーを使用するから、shrinkingの動作がより予測可能で理解しやすくなるのじゃ。サンプルのドロップや値の増加が発生しないからの。

roboko
ロボ子

予測可能性が高いのは良いですね。`QuickCheck`のintegrated shrinkingはmonadic bindを跨いで動作しないとのことですが、`falsify`はどうなんですか?

hakase
博士

`falsify`のinternal shrinkingは、generatorを独立してshrinkできない代わりに、generatorに供給するサンプルをshrinkするのじゃ。これにより、monadic bindを跨いでもshrinkingがうまくいくぞ。

roboko
ロボ子

`falsify`はselective functorであり、`select`メソッドを持つんですね。これにより、generatorが必要な場合にのみサンプルツリーをshrinkできると。

hakase
博士

その通り!`tasty`との統合により、`falsify`を簡単に使用開始できるのじゃ。`Property`はモナドであり、モナドのコンビネータが利用可能で、`gen`はgeneratorを実行し、generatorの出力をテストログに追加するのじゃ。

roboko
ロボ子

`Gen.int`は`Integral`型の値を生成し、`Range`は値の生成範囲とshrink方法を指定するんですね。

hakase
博士

そうそう!述語を使用すると、predicateが満たされない場合に意味のあるメッセージを生成できるし、`withOrigin`はshrinkの原点を指定し、`between`は値の範囲を指定、`skewedBy`は値の分布を歪めることができるのじゃ。

roboko
ロボ子

色々な機能があるんですね。

hakase
博士

`falsify`は関数を生成、表示、およびshrinkできるのじゃ。`fun`ジェネレーターを使用するぞ。`testShrinkingOfGen`を使用して、generatorのshrinking動作をテストできるし、`testMinimum`を使用して、特定のプロパティとgeneratorに対して特定の最小値を生成できることをテストできるのじゃ。

roboko
ロボ子

互換性はどうですか?

hakase
博士

`shrinkWith`と`fromShrinkTree`は、それぞれ`QuickCheck`と`hedgehog`スタイルのshrinkingとの互換性を提供するのじゃ。

roboko
ロボ子

`falsify`は、`Hypothesis`のコアアイデアをHaskellに適用し、予測可能なshrinkingとgeneratorの独立性制御を提供するんですね。勉強になりました!

hakase
博士

ふむ、今日は`falsify`について色々話したけど、ロボ子、もしテストが全部パスしたらどうする?

roboko
ロボ子

全部パスしたら、それは素晴らしいことですね!

hakase
博士

違うのじゃ!全部パスしたら、もうテスト書くのやめるのじゃ!

⚠️この記事は生成AIによるコンテンツを含み、ハルシネーションの可能性があります。

Search