5

私は を使った最初の実際の作業を行っていsmallcheckますが、パラメーターの使用方法について少し混乱していDepthます。その前に、私が何smallcheckのために使っているかを述べさせてください。

仕事では、社内データベースの前に単純な Web サービスを構築しています。Web サービスはいくつかのクエリを実行し、JSON にシリアル化されたクエリ結果で応答します。私が現在取り組んでいるのは、クエリの結果を表すオブジェクトが与えられた場合、このオブジェクトが期待される JSON を生成するという保証です。例えば:

data Action
  = Action { actionType :: !ActionType 
           , actionDescription :: !Text
           , actionPerformedAt :: !UTCTime
           , actionAgentName :: !Text
           }

次のような JSON を生成する必要があります。

{
  "type": "Booking",
  "description": "Whatever",
  "performedAt": "2012-01-04",
  "agent": "Tom"
}

これは にとって理想的なタスクのように見えましたsmallcheck。私はこれを次のように定式化しました。

testAction :: Tasty.TestTree
testAction = Tasty.testGroup "Action"
  [ SmallCheck.testProperty "type" $
      SmallCheck.over actions $ match $
        Aeson.key "type" --> Aeson.toJSON . actionType

  , SmallCheck.testProperty "dateActioned" $
      SmallCheck.over actions $ match $
        Aeson.key "dateActioned" --> expectedUTCTimeEncoding . actionPerformedAt

  -- and so on
  ]

-- (-->) :: Eq a => lens-aeson traversal a -> (b -> a) -> b -> Bool
-- actions :: Monad m => SmallCheck.Series m Action

フレームワークのデフォルトのsmallcheck深さtastyは 5 です。これにより、まだ終了していないテスト実行が行われます。smallcheckにはchangeDepthchangeDepth1関数があるため、これらを使用して、テストが常に適切な時間内に実行されるようにすることができます。changeDepth (const 3)だけど、こうするとどこかズレてる気がして仕方ないのでは?たとえば、コマンド ライン オプションを変更してテストを実行するだけでは、より長いテスト (おそらく一晩中) を実行することはできなくなりました。一方、 を使用changeDepth (- 2)した場合でも、テストがどのように実行されるかを仮定しているように感じます! おそらく、5 のグローバル テスト深さはn秒で実行され、適切と思われる深さを調整するのは各プロパティ次第であると仮定するのが最善でしょうか?

のこのより実用的な側面について、フィードバックをお待ちしておりますsmallcheck

4

2 に答える 2

5

QuickCheck のランダム テストを使用してテストする場合、唯一のメトリックはテストの数です。そのため、余裕のある限り多くのテストを行うのが自然です。

SmallCheck は、何がテストされているかについて実際に推論できるという点で異なります。理想的には、深さをテスト結果の信頼性と相関する単なる指標として扱うべきではありませんが、必要な深さについてはよく考えておく必要があります。

JSON について話している場合、JSON を処理するほとんどの関数は、一度に 1 層、場合によっては 2 層の構造で動作します。バグがあるとすれば、大雑把に言えば深さ 2 か 3 の構造で発見できます。(インスタンスに基づいて、必要な構造の深さを与える smallcheck の深さを見つけるか計算する必要がありSerialます。)

したがって、あなたの質問に答えるには、深さ 3 が許容できる最大の場合、まず、テストしている種類のコードに十分かどうかを判断する必要があります

たまたま十分でない場合は、幅を深さと交換するか (たとえば、葉の値の深さを減らすことによって)、または実際に QuickCheck のランダム列挙戦略に切り替えることができます。

構造のコンポーネントのローカルな組み合わせとは対照的に、テストしている関数に構造のサイズが原因でバグがあると思われる場合にのみ、QuickCheck を使用する必要があると思います。私が考えることができるいくつかの例は次のとおりです。

  • 数値オーバーフロー
  • 未発見の任意のハードコードされた制限 (おそらく外国の C コード — これは Haskell コードでは非常に非典型的です)
于 2013-12-09T11:15:51.137 に答える
3

smallcheck の「網羅性」は (とにかく小さなケースに対して) 興味深い特性ですが、このコンテキストではむしろ quickcheck をお勧めします。JSON は軽量な構造を持っていますが、実際のデータのビットの観点からはかなり重いです。

テスト時間は、型の Series インスタンスで smallcheck の「サイズ」(深さ) をどのように定義するかによっても大きく異なります。型に多くの分岐 (多くのコンストラクター) がある場合、テストの数は急速に増加します。「深さ」は指数関数的ですが、指数関数のベースは、特定のテストケースに関連する Series インスタンスの分岐の量です。

言い換えれば、平均して 2 つのコンストラクターがある場合、実行するテストケースは 32 程度ですが、20 の場合は 3200000 ほどになります。

ただし、カバレッジも同様に影響を受けます。テストケースで分岐を減らす (深さの増加を速くする) と、特定の深さで得られるカバレッジが少なくなります。クイックチェックを使用すると、「小さな」テストケースのいくつかを失うことと引き換えに、smallcheck では到達できない多くのより大きな例をサンプリングすることができます。

于 2013-11-20T10:48:46.350 に答える