Avoiding duplicated QuickCheck properties
I'm starting to learn Haskell by doing the 99 Haskell problems. http://www.haskell.org/haskellwiki/H-99:_Ninety-Nine_Haskell_Problems I'd like to write tests for each program/function using quickcheck.
I have the following code:
import Test.QuickCheck import Text.Printf main = mapM_ (\(s,a) -> printf "%-25s: " s >> a) tests -- 1 myLast lst = last lst prop_1a xs x = myLast (xs ++ [x]) == (x::String) myLast' = head . reverse prop_1b xs x = myLast' (xs ++开发者_如何学C [x]) == (x::String) tests = [("1a", quickCheck prop_1a) ,("1b", quickCheck prop_1b) ]
I might write myLast''
, myLast'''
, etc. Is there a way I can test all those methods without having to duplicate code and quickcheck properties?
Related question: Right now, I'm telling quickcheck to use Strings. Is there a way to randomly use different types to test against?
Just take the function to test as another argument:
prop_1 last xs x = last (xs ++ [x]) == (x :: Int)
tests = zipWith mkTest ['a'..] [myLast, myLast']
where mkTest letter func = ('1':[letter], quickCheck $ prop_1 func)
Is there a way I can test all those methods without having to duplicate code and quickcheck properties?
Why not write the prop so that it takes a list of functions, and then does the check on each of them? Then you'd run it as quickCheck (myProp [myLast, myLast', myLast''])
.
edit: I was afraid you might ask that :P To do it as I said above, myProp
should take a list of functions, all of which have the same type as last
, and return a boolean:
myProp :: [([a] -> a)] -> Bool
But now that I look at it, it might be better (and more analogous to your original approach) to have it also take a list and an item, so I think I'll do that instead:
myProp :: [([a] -> a)] -> [a] -> a -> Bool
If the list is empty then we return true:
myProp [] _ _ = True
If not, then we check whether the property holds for the first function in the list, then recursively check the rest of the list:
myProp [f:fs] xs x = f (xs ++ [x]) == x && myProp fs xs x
(I'm not sure why you wrote x::String
in your implementation. I don't think you should need it -- last
works on lists of anything, not just lists of Strings. But I haven't actually tested this out so I assume you had a good reason.)
Anyway, I think that should work but I haven't actually tried it. Please feel free to edit and fix any dumb syntax errors I may have made or whatever.
精彩评论