Testing IO actions with Monadic QuickCheck

痞子三分冷 提交于 2019-12-18 10:06:13

问题


Can anyone give me a brief example of testing IO actions using Monadic QuickCheck?


回答1:


The Test.QuickCheck.Monadic module lets you test monadic code, even things that run in IO.

A monadic property test is of type PropertyM m a, where m is the monad the test runs in and a is ultimately ignored. In the case of PropertyM IO a, you convert the monadic test to a Property by using monadicIO; for all other monads, you use monadic instead (which takes a function to run the monad, something IO doesn't have).

In a monadic test, the value returned out of the monad is ignored. To check an expression, use assert; asserting a false value will fail the test. Use run to execute the code in the monad being tested.

There are other monadic actions at your disposal. For example, pick will generate new test inputs out of a Gen a, and pre will check test preconditions. These are useful if the test inputs or preconditions themselves depend on values computed via the monad being tested, in which case the normal way of generating inputs or checking precontions won't work.

Here's an example of testing some IO code: we check that after writing something to a temporary file, we can read that same data back. For demonstration purposes, we'll impose the precondition that we write at least one byte to the file. The two test properties do the same thing; one uses pick and pre unnecessarily while the other does not.

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



回答2:


The standard reference for testing monadic code is "Testing Monadic Code with QuickCheck". It shows various ways of testing in the context of a monad such as IO.

But you should really consider posting a more concrete question about what it is that you would like to test.



来源:https://stackoverflow.com/questions/2259926/testing-io-actions-with-monadic-quickcheck

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!