使用QuickCheck测试故意错误情况

Dan*_*Dan 5 haskell quickcheck

我已经看到QuickCheck如何用于测试monadic和非monadic代码,但是如何使用它来测试处理错误的代码,即打印一些消息然后调用exitWith

nic*_*kie 4

首先声明一下:我不是 QuickCheck 方面的专家,在你提出问题之前我没有单子检查的经验,但我认为 stackoverflow 是一个学习新东西的机会。如果有专家回答说这可以做得更好,我会删除我的。

test假设您有一个可以使用 引发异常的函数exitWith。我认为您可以通过以下方式进行测试。关键函数是protect,它捕获异常并将其转换为可以测试的内容。

import System.Exit
import Test.QuickCheck
import Test.QuickCheck.Property
import Test.QuickCheck.Monadic

test :: Int -> IO Int
test n | n > 100   = do exitWith $ ExitFailure 1
       | otherwise = do print n
                        return n

purifyException :: (a -> IO b) -> a -> IO (Maybe b)
purifyException f x = protect (const Nothing) $ return . Just =<< f x

testProp :: Property
testProp = monadicIO $ do
  input <- pick arbitrary
  result <- run $ purifyException test $ input
  assert $ if input <= 100 then result == Just input
                           else result == Nothing
Run Code Online (Sandbox Code Playgroud)

据我所知,这样做有两个缺点,但我没有找到克服它们的方法。

  1. ExitCode我发现没有办法从可以处理的异常中AnException提取异常protect。因此,所有退出代码在这里都被同等对待(它们被映射到Nothing)。我希望有:

    purifyException :: (a -> IO b) -> a -> IO (Either a ExitCode)
    
    Run Code Online (Sandbox Code Playgroud)
  2. 我发现没有办法测试 test 的 I/O 行为。假设test是:

    test :: IO ()
    test = do
      n <- readLn
      if n > 100 then exitWith $ ExitFailure 1
                 else print n
    
    Run Code Online (Sandbox Code Playgroud)

    那你会如何测试呢?

我也希望得到更多专家的解答。