使用快速检查的上下文敏感生成

时间:2018-03-18 01:50:35

标签: haskell quickcheck

我想基于某种“上下文”生成随机术语,我想知道使用quickcheck是否可行。基本上我想传递一个额外的数据类型,以便任意函数可以根据附加参数生成术语......这是否可以通过快速检查或者我应该编写自己的Gen定义?

2 个答案:

答案 0 :(得分:2)

arbitrary内执行此操作是可能的,尽管不是很明智。但如果你走出arbitrary,你可以字面上只是传递一个额外的参数。

-- do whatever you want inside the implementation of these two
chooseIntRange :: Context -> Int
updateContext :: Int -> Context -> Context

arbitraryIntWithContext :: Context -> Gen (Context, Int)
arbitraryIntWithContext ctx = do
    n <- choose (0, chooseIntRange ctx)
    return (n, updateContext n ctx)

使用StateT可以稍微减轻上下文的管道,例如

-- do whatever you want inside the implementation of this
chooseIntRangeAndUpdate :: MonadState Context m => m Int

arbitraryIntStateT :: StateT Context Gen Int
arbitraryIntStateT = do
    hi <- chooseIntRangeAndUpdate
    lift (choose (0, hi))

答案 1 :(得分:1)

虽然Daniel Wagner为QuickCheck(+1)提供了一个很好的答案,但它也突出了QuickCheck的一个弱点。在QuickCheck中,使用Arbitrary的实例编写属性,但由于其设计,Arbitrary不是monadic。

Daniel Wagner分享的解决方法是Gen,另一方面, monadic,因此您可以使用do表示法编写与上下文相关的代码。缺点是,虽然您可以将Gen a转换为Arbitrary a,但您必须提供自定义shrink实施,或者放弃缩小。

基于属性的测试的替代库Hedgehog,其设计方式使得属性本身是monadic,这意味着您可以编写整个属性并简单地嵌入ad-hoc测试代码本身中特定于上下文的值生成(包括缩小):

propWithContext :: Property
propWithContext = property $ do
  ctx <- forAll genContext
  n <- forAll $ Gen.integral $ Range.linear 0 $ chooseIntRange ctx
  let ctx' = updateContext n ctx

  -- Exercise SUT and verify result here...

此处,genContextContext类型的自定义生成器,类型为

genContext :: MonadGen m => m Context