12

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

考虑例如:

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

然后会话可能如下所示:

> quickCheck prop
Falsifiable, after 48 tests:
42
23

但是对于调试来说,将失败的原因显示为 quickCheck falsifable 报告的一部分会非常方便。

我已经这样破解了它:

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

有没有更好/更好或更快速的方法来做到这一点?

4

4 回答 4

10

我假设您的“原因”变量包含某种特定于测试的数据,说明出了什么问题。您可以改为返回“结果”,其中包含成功/失败/无效条件和解释问题所在的字符串。返回结果的属性由 QuickCheck 处理,其处理方式与返回 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.P​​roperty 中定义的“结果”类型。

Test.QuickCheck.P​​roperty 中还定义了一些组合器,它们可以帮助您组合 Result 而不是直接调用构造函数,例如

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

我想使用这些会更好。

于 2011-01-23T18:13:06.770 回答
2

因为 QuickCheck 为您提供了函数的输入,并且由于被测代码是纯代码(它是,对吗?),您可以将这些输入提供给函数并获得结果。这更加灵活,因为使用这些输入,您还可以通过调整原始函数来重复测试,直到它正确为止。

于 2011-01-23T11:34:04.567 回答
2

这与 Paul Johnson 的答案相同,但对 中的变化更加简洁和稳健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
于 2018-05-29T16:04:07.403 回答
1

这是我的解决方案(我使用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)

您还可以<?>.&&..||.===一起使用==>

  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"
于 2018-11-28T09:11:10.347 回答