Haskell, IO, monads, quickcheck

2019-09-05 23:07发布

问题:

Beginner at Haskell here.

I have a function, and a bunch of properties to test it with which I've written using quickcheck. The properties work when I run them individually in the interpreter, and the function checks out fine.

However, manually quickchecking with each property in the interpreter by hand (quickCheck prop_this, quickCheck prop_that) is boring, monotonous, and time-consuming. I would like to stick all of this in a program, and have that program run all of the quickchecks. This is where I am stuck.

The basic skeleton of the program is as follows:

imports...

function_which_i_want_to_quickcheck

prop_1
prop_2
etc...

main = do
    quickCheck prop_1
    quickCheck prop_2
    etc...

Everything above main is fine I believe, as it all compiles and works without it. main is what I need help with. I've tried several variations, i.e. not having a do, using a do, assigning results using 'x <- quickCheck y', removing quickCheck from the inside and sticking it on the outside instead, etc. but can't get anything to work.

  1. Can anyone assist with the above?

  2. If I wanted to move everything inside main to another (normal, non-main) function, how would I do it?

EDIT: I appreciate the recommendation for testing frameworks, but what I'm asking for here is trivial to do in any other language, and shouldn't need a testing framework. Why not Haskell?

Also, this works correctly right inside the interpreter. I can't get it to work inside main. Any ideas why?

quickCheck prop_1 >> quickCheck prop_2 >> quickCheck prop_3

Thanks.

回答1:

It is not very clear from the question what problems you have, but generally I'd recommend using a testing framework, such as tasty, to organize your quickcheck tests together:

import Test.Tasty
import Test.Tasty.QuickCheck

main = defaultMain $ testGroup "Tests"
  [ testProperty "+ is commutative" $
      \x y -> x + y == (y + x :: Double)
  , testProperty "+ is associative" $
      \x y z -> (x + y) + z == (x + (y + z) :: Double)
  ]

To run this, you'll need to install the tasty-quickcheck package.

Here's how it looks when executed:



回答2:

I've used TestFramework in the past. It allows you to create arbitrarily nested test groups, which gives you a way to change input parameters.

main = do
    defaultMain $ [tier1_tests, ...]

tier1_tests = testGroup "Level One Tests" [tier2_tests1, tier2_tests2, ...]

tier2_tests1 = testGroup "Level Two Testgroup 1" [tier3_tests1, youGetTheIdea, ...]
                 ] 
tier3_tests1 = testGroup "Level Three Testgroup" [
        testProperty "m=32 random encoding with good x" (prop_realTest1 8 32 True),
        testProperty "m=256 random encoding bad x" (prop_realTest2 128 256 False),
        ... ]

prop_realTest1 m goodq b = forAll arbitrary (\ x -> ...)