通过QuickCheck进行测试时,显示出属性测试失败的原因的最佳实践是什么?

例如,请考虑:

prop a b = res /= []
   where
      (res, reason) = checkCode a b

然后,A会话看起来像:

> quickCheck prop
Falsifiable, after 48 tests:
42
23

但是对于调试,将失败的原因作为QuickCheck Falsififififififififififififififififififififififififififififififififififfalsiffalsive for dibug。

我这样砍了它:

prop a b = if res /= [] then traceShow reason False else True
   where
      (res, reason) = checkCode a b

有更好/更好或更好的快速检查方法吗?

有帮助吗?

解决方案

我认为您的“原因”变量包含有关出现问题的某种特定于测试的数据。相反,您可以返回一个“结果”,该“结果”既包含成功/失败/无效的条件,又包含一个说明出了问题的字符串。返回结果的属性通过Quick检查以与返回bool的属性完全相同的方式处理。

(编辑)这样:

module QtTest where 

import Test.QuickCheck
import Test.QuickCheck.Property as P


-- Always return success
prop_one :: Integer -> P.Result
prop_one _ = MkResult (Just True) True "always succeeds" False [] []


-- Always return failure
prop_two :: Integer -> P.Result
prop_two n = MkResult (Just False) True ("always fails: n = " ++ show n) False [] []

请注意,这是您想要的test.quickcheck.property中定义的“结果”类型。

test.quickcheck.property中还定义了一些组合器,可以帮助您构成结果,而不是直接调用构造函数,例如

prop_three :: Integer -> Property
prop_three n = printTestCase ("always fails: n = " ++ show n) False

我想使用这些风格是更好的风格。

其他提示

因为QuickCheck为您提供了该函数的输入,并且由于测试的代码是纯的(对吗?),因此您可以将这些输入馈送到功能并获得结果。这是更灵活的,因为使用这些输入,您也可以对原始功能进行调整,直到正确为止。

这是我的解决方案(我使用 counterexample 代替 printTestCase 由于现在被弃用了):

(<?>) :: (Testable p) => p -> String -> Property
(<?>) = flip (Test.QuickCheck.counterexample . ("Extra Info: " ++))
infixl 2 <?>

用法:

main :: IO ()
main = hspec $ do
  describe "math" $ do
    prop "sum-of-square-le-square-of-sum" $ do
      \(x :: Int) (y :: Int) ->
        x * x + y * y <= (x + y) * (x + y) <?> show (x * x, y * y, x + y)

因此,当测试案例失败时,您可以看到类似的东西:

   *** Failed! Falsifiable, Falsifiable (after 2 tests):
   1
   -1
   Extra Info: (1,1,0)

您也可以使用 <?> 和...一起 .&&., .||., =====> ETC。:

  describe "math" $ do
    prop "sum-of-square-le-square-of-sum" $ do
      \(x :: Int) (y :: Int) ->
        x * x + y * y <= (x + y) * (x + y) <?> show (x * x, y * y, x + y) .||. (1==0) <?> "haha"

这与保罗·约翰逊的回答相同,但对变化更简洁和强大 MkResult:

import Test.QuickCheck.Property (succeeded, failed, reason)

prop a b =
  if res /= []
    then succeeded
    else failed { reason = reason }
   where
      (res, reason) = checkCode a b
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top