Как отобразить причину неудачного тестового свойства с помощью QuickCheck?

StackOverflow https://stackoverflow.com/questions/4772902

  •  23-10-2019
  •  | 
  •  

Вопрос

Какова наилучшая практика для отображения причин неудачного теста свойства, когда он тестируется через QuickCheck?

Рассмотрим, например:

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

Тогда сеанс может выглядеть как:

> quickCheck prop
Falsifiable, after 48 tests:
42
23

Но для отладки было бы очень удобно показать причину неудачи в рамках отчета о быстрого разжигания QuickCheck.

Я взломал это так:

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

Есть ли лучший/приятный или более быстрый способ сделать это?

Это было полезно?

Решение

Я предполагаю, что ваша переменная «разум» содержит какие-то конкретные данные о том, что пошло не так. Вместо этого вы можете вернуть «результат», который содержит как успех/неверный/недопустимые условия, и строка, объясняющая, что пошло не так. Свойства, которые возвращают результаты, обрабатываются 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.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)

Вы также можете использовать <?> вместе с .&&., .||., === а также ==> так далее.:

  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