【问题标题】:Haskell / SmallCheck: How to control the `Depth` parameter?Haskell / SmallCheck:如何控制“深度”参数?
【发布时间】:2013-12-14 11:36:08
【问题描述】:

我有一个简单的数据结构要在 smallcheck 中进行测试。

{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
{-# LANGUAGE DeriveGeneric #-}

import Test.Tasty
import Test.Tasty.SmallCheck
import Test.SmallCheck.Series
import GHC.Generics

data T1 = T1 { p1 :: Int,
               p2 :: Char,
               p3 :: [Int]
             } deriving (Eq, Show, Generic)

instance Monad m => Serial m T1

main :: IO ()
main = defaultMain tests

tests :: TestTree
tests = testGroup "Tests" [scProps]

scProps = testGroup "(checked by SmallCheck)"
  [ testProperty "Test1" prop_test1
  ]

prop_test1 x = x == x
             where types = (x :: T1)

在运行测试时,是否有任何通用解决方案可以为(单个)测试设置 Depth 参数,或者更好的是,为单个字段设置 Depth 参数的细粒度解决方案,例如将p3的深度限制为2,避免搜索空间的组合爆炸?

非常感谢!

朱尔斯

信息: 一个有点相关的问题是here

编辑:
我采用了Roman Cheplyaka 接受的答案中给出的解决方案,并在一个最小的工作示例中实现了它们(感谢 Roman):

{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}

import Test.Tasty
import Test.Tasty.Options
import Test.Tasty.SmallCheck
import Test.SmallCheck.Series
import Data.Functor
-- =============================================================================
main :: IO ()
main = defaultMain tests
-- =============================================================================
-- the data structure to be tested
data T1 = T1 { p1 :: Int,
               p2 :: Char,
               p3 :: Int,
               p5 :: [Int]
             } deriving (Show, Eq)
-- =============================================================================
-- some test-properties
prop_test1 x y = x == y
               where types = (x :: T1, y :: T1)
prop_test2 x = x == x
             where types = (x :: T1)
-- =============================================================================
-- how to change the depth of the search spaces?
{-| I Possibility: Command Line |-}
-- foo@bar$ runhaskell Test.hs --smallcheck-depth 2

-- -----------------------------------------------------------------------------
{-| II Possibility: |-}
-- normal:
-- tests :: TestTree
-- tests = testGroup "Tests" [scProps]

-- custom:
tests :: TestTree
tests = localOption d $ testGroup "Tests" [scProps]
      where d = 3 :: SmallCheckDepth

scProps = testGroup "(checked by SmallCheck)"
  [ testProperty "Test1" prop_test1, 
    testProperty "Test2" prop_test2 
  ]

-- -----------------------------------------------------------------------------
{-| III Possibility: Adjust Depth when making the type instance of Serial |-}
-- normal:
-- instance (Monad m) => Serial m T1 where
--   series = T1 <$> series <~> series <~> series <~> series 

-- custom:
instance (Monad m) => Serial m T1 where
    series = localDepth (const 4) $ T1 <$> (localDepth (const 2) series) <~> series <~> series <~> (decDepth series) 

-- (a few more examples):
-- instance (Monad m) => Serial m T1 where
--    series = decDepth $ T1 <$> series <~> series <~> series <~> (decDepth series ) 
-- instance (Monad m) => Serial m T1 where
--   series = localDepth (const 3) $ T1 <$> series <~> series <~> series <~> series 
-- instance (Monad m) => Serial m T1 where
--    series = localDepth (const 4) $ T1 <$> series <~> series <~> series <~> (decDepth series) 

【问题讨论】:

  • stackoverflow.com/questions/15959357/…——几个小时前我正在寻找这个问题的答案,偶然发现了这个链接。
  • @jules 关于您的编辑,我想指出的是,没有必要只选择一种方式并确定深度(尽管您可以根据需要)。如果您使用相关函数(adjustOptionlocalDepth 没有 const),这些控件可以很好地组合。特别是,在 SmallCheck 中使用 localDepth . const 并不是一个好主意。

标签: testing haskell automated-tests smallcheck


【解决方案1】:

我将首先列出taste & smallcheck 提供的开箱即用的控制方式:

  • 运行测试套件时,您可以通过--smallcheck-depth 选项来控制«common»深度
  • 编写测试套件时,您可以使用adjustOption 调整任何子树相对于命令行(或父树)指定的深度
  • 最后,在编写串行实例时,您可以使用localDepth 来调整每个特定字段的深度,相对于整个结构的深度。通常它是整体深度 - 1(这是 decDepth 在标准定义中所做的),但您可以发明自己的规则。

因此,这种控制是可能的,尽管是以间接的方式。通常这就是你想要的——另见this answer

如果您真的想在运行时控制单个字段的深度...是的,这是可能的,尽管它有点复杂,因为它不是预期的用例。 (不过,有可能实现这一点还是很酷的!)Here's a working example.

如果这个功能对你很重要,可以在 github 上打开一个问题并解释你为什么需要它。 (但首先,请务必阅读我对上面链接的 ocharles 的回复。您很少需要在运行时调整深度。)

【讨论】:

    【解决方案2】:

    总结和举例说明,假设您想尝试深度为 2,您有多种选择。

    直接运行测试套件(可执行)时:

    ./test --smallcheck-depth 2
    

    从 cabal 运行测试套件时:

    cabal test --test-options="--smallcheck-depth 2"
    

    通过更改 testGroup/TestTree 中的深度:

    -- Global depth + 1  (usually supplied by command line)
    props = adjustOption (+ SmallCheckDepth 1) $
            testGroup "some props"
              [ SC.testProperty myProp1
              , SC.testProperty myProp2
              ]
    
    -- Local depth = 2
    prps2 = localOption (SmallCheckDepth 2) $
            testGroup "fixed depth"
            [ ... ]
    

    adjustOptionlocalOption 也可用于特定属性。我个人认为 adjustOption 更可取,因为它只是调整命令行提供的任何内容或任何封闭的TestTree

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-18
    • 1970-01-01
    • 1970-01-01
    • 2018-10-26
    • 2015-10-11
    • 2015-01-22
    相关资源
    最近更新 更多