使用QuickCheck为给定函数生成多个任意参数

时间:2017-08-05 08:40:35

标签: haskell typeclass quickcheck

上下文

我有以下功能:

prop_SignAndVerify :: (PrivKey a b) => Blind a -> BS.ByteString -> Bool
prop_SignAndVerify bsk msg = case verify pk msg sig of
                             Left e -> error e
                             Right b -> b
  where
    sk  = getBlind bsk
    pk  = toPublic sk
    sig = case sign sk msg of
               Left e -> error e
               Right s -> s

我想做点什么:

-- instance PrivKey RSA.PrivateKey RSA.PublicKey where...
genRSA :: Gen RSA.PrivateKey
genRSAMessage :: Gen BS.ByteString

main = do
  quickCheck . verbose 
  $ forAll genRSA 
  $ forAll genRSAMessage prop_SignAndVerify

也就是说,我想使用显式生成器在Blind a的参数中为BS.ByteStringprop_SignAndVerify生成任意值。

但上面的代码不起作用,因为函数forAll具有类型签名:

forAll :: (Show a, Testable prop) => Gen a -> (a -> prop) -> Property

此函数运行生成器并将生成的任意值加到(a -> prop),返回Property。但Property不能进一步部分应用;它隐藏了潜在的功能。

我认为上述工作需要的是:

forAll' :: (Show a,  Testable prop) => Gen a -> (a -> prop) -> prop

问题

所以我的问题是,如何在genRSA的参数上使用genRSAMessageprop_SignAndVerify,还是有替代方法?

由于

2 个答案:

答案 0 :(得分:6)

您想检查prop_SignAndVerify key message 所有多个keymessage。因此,如果我们有一个固定的key,我们的测试将如下所示:

main = do
  quickCheck . verbose $ 
    let key = someGeneratedKey
    in forAll genRSAMessage $ \message ->
         prop_SignAndVerify key message

如果我们有一个固定的message,我们的测试将如下所示:

main = do
  quickCheck . verbose $ 
    forAll genRSAMessage $ \key ->
      let message = someMessage
      in prop_SignAndVerify key message

我们所要做的就是结合两种变体:

main = do
  quickCheck . verbose $ 
    forAll genRSA        $ \key ->
    forAll genRSAMessage $ \message ->
      prop_SignAndVerify key message

由于eta转换,您可以摆脱message,但在我看来,测试应该易于阅读。

答案 1 :(得分:2)

您可以利用Gen的monadic性质来构建属性中更复杂的Gen值:

main =
  let g = do
            key <- genRSA
            message <- genRSAMessage
            return $ prop_SignAndVerify (Blind key) message
  in quickCheck . verbose $ forAll g id

此处,gGen Bool值。

或者,您可以利用Gen的适用性,并使用g撰写<*>

main =
  let g =
        return (\key message -> prop_SignAndVerify (Blind key) message)
        <*> genRSA
        <*> genRSAMessage
  in quickCheck . verbose $ forAll g id

g此处仍为Gen Bool值。