Search code examples
haskellquickcheck

How to prevent tested functions from outputting to terminal when using QuickCheck monadicIO


I'm wondering if there's some way to prevent functions from printing to the terminal when they're being tested through GHCI with QuickCheck and monadicIO.

For example, say I have the following code:

import Test.Hspec
import Test.Hspec.QuickCheck
import Test.QuickCheck
import Test.QuickCheck.Monadic (assert, monadicIO, pick, run)

main :: IO ()
main = hspec $ do
  describe "Something to test" $ do
    it "What I'm testing" $ do
      prop_exampleTest

prop_exampleTest :: Property
prop_exampleTest = monadicIO $ do
  num    <- pick arbitrary
  newNum <- run $ exampleFunc num
  assert $ num == newNum

I just want to test the return value of exampleFunc. However, if it uses putStrLn, then it will print to the terminal with each check.

exampleFunc :: Int -> IO Int
exampleFunc n = do
  putStrLn "One trick is to tell 'em stories that don't go anywhere - like the time I caught the ferry over to Shelbyville. I needed a new heel for my shoe, so, I decided to go to Morganville, which is what they called Shelbyville in those days. So I tied an onion to my belt, which was the style at the time. Now, to take the ferry cost a nickel, and in those days, nickels had pictures of bumblebees on 'em. Give me five bees for a quarter, you'd say..."
  return n

Is there any way to prevent this?


Solution

  • As bradrn commented, this can be done using the silently package. Just apply your function as an argument to its silence function:

    import Test.Hspec
    import Test.Hspec.QuickCheck
    import Test.QuickCheck
    import Test.QuickCheck.Monadic (assert, monadicIO, pick, run)
    -- Add the import statement for the silently 'silence' function.
    import System.IO.Silently (silence)
    
    main :: IO ()
    main = hspec $ do
      describe "Something to test" $ do
        it "What I'm testing" $ do
          prop_exampleTest
    
    prop_exampleTest :: Property
    prop_exampleTest = monadicIO $ do
      num    <- pick arbitrary
      -- instead of running my function directly, apply it as an argument to silence
      newNum <- run $ silence (exampleFunc num)
      assert $ num == newNum
    
    
    exampleFunc :: Int -> IO Int
    exampleFunc n = do
      putStrLn "One trick is to tell 'em stories that don't go anywhere - like the time I caught the ferry over to Shelbyville. I needed a new heel for my shoe, so, I decided to go to Morganville, which is what they called Shelbyville in those days. So I tied an onion to my belt, which was the style at the time. Now, to take the ferry cost a nickel, and in those days, nickels had pictures of bumblebees on 'em. Give me five bees for a quarter, you'd say..."
      return n