题
通过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
不隶属于 StackOverflow