【问题标题】:context-sensitive generation using quick check使用快速检查的上下文相关生成
【发布时间】:2018-08-26 21:07:35
【问题描述】:

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

【问题讨论】:

    标签: haskell quickcheck


    【解决方案1】:

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

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

    另一个用于基于属性的测试的库 Hedgehog 的设计方式是属性本身是一元的,这意味着您可以编写整个属性并简单地嵌入特定于上下文的特定值测试代码本身的生成(包括收缩):

    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
    

    【讨论】:

      【解决方案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))
      

      【讨论】:

      • 感谢您的回答!我可以看到如何更改它以使用多态类型并从中创建一个 ContextArbitrary 类型类
      猜你喜欢
      • 1970-01-01
      • 2019-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多