16

プロパティテストは何を目指しているのか、スイートポイントは何なのか、どこで使うべきなのか知りたいです。テストしたい関数の例を見てみましょう:

f :: [Integer] -> [Integer]

この関数 はf、数値のリストを取り、奇数を 2 乗し、偶数を除外します。次のように、関数に関するいくつかのプロパティを述べることができます

  1. 偶数のリストを指定すると、空のリストを返します。
  2. 奇数のリストを指定すると、結果リストは入力と同じサイズになります。
  3. 偶数のリストと奇数のリストがあるとすると、それらを結合し、シャッフルして関数に渡すと、結果の長さは奇数のリストの長さになります。
  4. 正の奇数のリストを指定すると、同じインデックスにある結果リストの各要素は元のリストよりも大きくなります
  5. 奇数と偶数のリストを提供し、それらを結合してシャッフルすると、各番号が奇数のリストが得られます

関数が最も単純なケースで機能することをテストするプロパティはありません。たとえば、f間違って実装した場合にこれらのプロパティを渡す単純なケースを作成できます。

f = fmap (+2) . filter odd

したがって、単純なケースをカバーしたい場合は、プロパティ仕様でアルゴリズムの基本的な部分を繰り返すか、値ベースのテストを使用する必要があるようです。私が持っている最初のオプションは、アルゴリズムを繰り返すのに役立つかもしれません。たとえば、速度のためにアルゴリズムの実装を変更する予定がある場合は、アルゴリズムを改善する予定です。このようにして、再度テストするために使用できる参照実装ができました。

いくつかの些細なケースでアルゴリズムが失敗しないことを確認したい場合、および仕様でアルゴリズムを繰り返したくない場合は、単体テストが必要なようです。たとえば、これらのチェックを記述します。

f ([2,5]) == [25]
f (-8,-3,11,1) == [9,121,1]

今では、アルゴリズムに自信を持っています。

私の質問は、プロパティ ベースのテストは単体テストに取って代わるものですか、それとも補完的なものですか? プロパティをどのように記述するかという一般的な考え方はありますか?それらは便利ですか、それとも関数のロジックの理解に完全に依存していますか? つまり、何らかの方法でプロパティを記述することは特に有益であると言えますか?

また、プロパティがアルゴリズムのすべての部分をテストするように努力する必要がありますか? アルゴリズムから 2 乗を除外して、別の場所でテストし、プロパティでフィルタリング部分だけをテストして、それが適切にカバーされているかどうかをテストすることができます。

f :: (Integer -> Integer) -> [Integer] -> [Integer]
f g = fmap g . filter odd

そして、単体テストを使用して合格し、他Prelude.idの場所をテストできます。g

4

2 に答える 2

3

参照アルゴリズム

(おそらく非効率的な) 参照実装を用意し、それに対してテストすることは非常に一般的です。実際、これは数値アルゴリズムを実装する際の最も一般的なクイックチェック戦略の 1 つです。しかし、アルゴリズムのすべての部分で必要なわけではありません。アルゴリズムを完全に特徴付ける特性がいくつかある場合があります。Ingo のコメントはその点で的を射ています: これらのプロパティは、アルゴリズムの結果を決定します (順序と重複まで)。順序と重複を回復するには、プロパティを変更して、「ソース要素の位置の後に切り捨てられた結果のリスト」を含めることができます。また、その逆も他のプロパティに含めることができます。

テストの粒度

もちろん、Haskell の構成可能性を考えると、アルゴリズムの合理的な小さな部分をそれぞれ単独でテストするのはよいことです。\x -> x*x私は、例えば、filter odd二度見せずに参照として信頼しています。

各部分にプロパティが必要かどうかは、後でアルゴリズムのその部分をインライン化してプロパティを無意味にする可能性があるため、明確ではありません。Haskell の怠惰のため、これは一般的ではありませんが、発生します。

于 2015-05-24T05:35:46.620 に答える