使用Monadic QuickCheck测试IO操作

时间:2010-02-14 02:27:15

标签: haskell io quickcheck

有人能给我一个使用Monadic QuickCheck测试IO操作的简短示例吗?

2 个答案:

答案 0 :(得分:57)

Test.QuickCheck.Monadic模块允许您测试monadic代码,甚至是IO中运行的代码。

monadic属性测试的类型为PropertyM m a,其中m是测试运行的monad,a最终会被忽略。对于PropertyM IO a,您可以使用Property将monadic测试转换为monadicIO;对于所有其他monad,你使用monadic代替(使用函数来运行monad,而IO没有)。

在monadic测试中,忽略monad中的值return。要检查表达式,请使用assert; assert假值将导致测试失败。使用run执行正在测试的monad中的代码。

您可以随意使用其他monadic行动。例如,pick将从Gen a生成新的测试输入,pre将检查测试前置条件。如果测试输入或前置条件本身依赖于通过被测试的monad计算的值,则这些非常有用,在这种情况下,生成输入或检查预置的常规方法将不起作用。

这是一个测试一些IO代码的示例:我们检查一下在写入临时文件之后,我们可以读回相同的数据。出于演示目的,我们将强加给文件写入至少一个字节的前提条件。两个测试属性做同样的事情;一个人不必要地使用pickpre,而另一个则没有。{/ p>

import System.Directory (removeFile)
import System.IO (hGetContents, hPutStr, hSeek, openBinaryTempFile, SeekMode (..))
import Test.QuickCheck (arbitrary, Property, quickCheck, (==>))
import Test.QuickCheck.Monadic (assert, monadicIO, pick, pre, run)

-- Demonstrating pick and pre as well:
prop_writeThenRead :: Property
prop_writeThenRead = monadicIO $ do writtenData <- pick arbitrary
                                    pre $ not (null writtenData)
                                    readData <- run $ writeThenRead writtenData
                                    assert $ writtenData == readData

-- A more idiomatic way to write the above:
prop_writeThenRead2 :: [Char] -> Property
prop_writeThenRead2 writtenData = not (null writtenData) ==> monadicIO test
    where test = do readData <- run $ writeThenRead writtenData
                    assert $ writtenData == readData

writeThenRead :: [Char] -> IO [Char]
writeThenRead output = do (path, h) <- openBinaryTempFile "/tmp" "quickcheck.tmp"
                          removeFile path
                          hPutStr h output
                          hSeek h AbsoluteSeek 0
                          hGetContents h

main :: IO ()
main = do quickCheck prop_writeThenRead
          quickCheck prop_writeThenRead2

答案 1 :(得分:7)

测试monadic代码的标准参考是"Testing Monadic Code with QuickCheck"。它显示了在monad(例如IO)的上下文中的各种测试方法。

但是你应该考虑发布一个更具体的问题,即你要测试的是什么。