我想基于某种“上下文”生成随机术语,我想知道使用quickcheck是否可行。基本上我想传递一个额外的数据类型,以便任意函数可以根据附加参数生成术语......这是否可以通过快速检查或者我应该编写自己的Gen定义?
答案 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...
此处,genContext
是Context
类型的自定义生成器,类型为
genContext :: MonadGen m => m Context