Подтвердить что ты не робот

Найдите значение, которое не удалось выполнить с помощью quickcheck

Когда значение не проходит тест QuickCheck'd, я бы хотел использовать его для отладки. Есть ли способ сделать что-то вроде:

let failValue = quickCheck' myTest
in someStuff failValue

Если мои данные были read способны, я мог бы взломать какой-то способ получить его из IO, но это не так.

4b9b3361

Ответ 1

Я не смог найти что-либо в QuickCheck API, чтобы сделать это красиво, но вот что-то, что я взломал вместе, используя монадический QuickCheck API. Он перехватывает и записывает входные данные в ваше свойство в IORef и предполагает, что если он не прошел, последний был виновником и возвращает его в Just. Если тест прошел, результат будет Nothing. Возможно, это немного уточняется, но для простых свойств с одним аргументом он должен выполнить эту работу.

import Control.Monad
import Data.IORef
import Test.QuickCheck
import Test.QuickCheck.Monadic

prop_failIfZero :: Int -> Bool
prop_failIfZero n = n /= 0

quickCheck' :: (Arbitrary a, Show a) => (a -> Bool) -> IO (Maybe a)
quickCheck' prop = do input <- newIORef Nothing
                      result <- quickCheckWithResult args (logInput input prop)
                      case result of
                         Failure {} -> readIORef input
                         _ -> return Nothing
  where
    logInput input prop x = monadicIO $ do run $ writeIORef input (Just x)
                                           assert (prop x)
    args = stdArgs { chatty = False }

main = do failed <- quickCheck' prop_failIfZero
          case failed of
              Just x -> putStrLn $ "The input that failed was: " ++ show x
              Nothing -> putStrLn "The test passed"

Ответ 2

Одним из способов было бы использовать метод sample ', вручную запустить тест и найти значения, в которых он терпит неудачу. Например, тестирование неисправной двойной функции:

import Test.QuickCheck

double :: Int -> Int
double x | x < 10 = 2 * x
         | otherwise = 13

doubleTest :: Int -> Bool
doubleTest x = x + x == double x

tester :: IO ()
tester = do
  values <- sample' arbitrary
  let failedValues = filter (not . doubleTest) values
  print failedValues

Единственная проблема: sample' генерирует только 11 тестовых значений, которые могут быть недостаточными для запуска ошибки.