使用快速检查的上下文敏感生成
context-sensitive generation using quick check
我想根据某种 "context" 生成随机术语,我想知道是否可以使用快速检查。基本上我想传递一个额外的数据类型,以便任意函数可以根据额外的参数生成术语......这可以用快速检查还是我应该写我自己的 Gen 定义?
从 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))
虽然 Daniel Wagner 为 QuickCheck (+1) 提供了一个很好的答案,但它也突出了 QuickCheck 的一个弱点。在 QuickCheck 中,使用 Arbitrary
的实例编写属性,但由于其设计,Arbitrary
不是一元的。
Daniel Wagner 分享的解决方法是 Gen
,另一方面, 是 monadic,因此您可以使用 [=15 编写上下文相关的代码=] 符号。缺点是虽然您可以将 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...
这里,genContext
是Context
类型的自定义生成器,类型为
genContext :: MonadGen m => m Context
我想根据某种 "context" 生成随机术语,我想知道是否可以使用快速检查。基本上我想传递一个额外的数据类型,以便任意函数可以根据额外的参数生成术语......这可以用快速检查还是我应该写我自己的 Gen 定义?
从 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))
虽然 Daniel Wagner 为 QuickCheck (+1) 提供了一个很好的答案,但它也突出了 QuickCheck 的一个弱点。在 QuickCheck 中,使用 Arbitrary
的实例编写属性,但由于其设计,Arbitrary
不是一元的。
Daniel Wagner 分享的解决方法是 Gen
,另一方面, 是 monadic,因此您可以使用 [=15 编写上下文相关的代码=] 符号。缺点是虽然您可以将 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...
这里,genContext
是Context
类型的自定义生成器,类型为
genContext :: MonadGen m => m Context