I want to go through 99 Haskell Problems, and I want to concentrate on the solution but with testing. If I have the solution to the first problem as a 3 line .hs
file,
myLast :: [a] -> a myLast [x] = x myLast (_:xs) = myLast xs
What is the minimal amount of code I can add to this so that I can add tests inline and run them with runhaskell
?
QuickCheck (which basicaly generates test inputs for you) is probably the best way to test pure function. And if a function in question has an analog from the standard library you can just test your function using the standard one as a model:
{-# LANGUAGE TemplateHaskell #-} import Test.QuickCheck import Test.QuickCheck.All myLast :: [a] -> a myLast [x] = x myLast (_:xs) = myLast xs -- here we specify that 'myLast' should return exactly the same result -- as 'last' for any given 'xs' prop_myLast xs = myLast xs == last xs return [] -- need this for GHC 7.8 -- quickCheckAll generates test cases for all 'prop_*' properties main = $(quickCheckAll)
If you run it you'll get:
=== prop_myLast on tmp3.hs:12 === *** Failed! Exception: 'tmp3.hs:(7,1)-(8,25): Non-exhaustive patterns in function myLast' (after 1 test): [] False
because your myLast
doesn't handle []
case (it should but should probably throw an error like 'last'). But here we can simply adjust our test but specifying that only non-empty strings should be used (using ==>
combinator):
prop_myLast xs = length xs > 0 ==> myLast xs == last xs
Which makes all 100 auto-generated test cases to pass for myLast
:
=== prop_myLast on tmp3.hs:11 === +++ OK, passed 100 tests. True
PS Another way to specify myLast
behavior may be:
prop_myLast2 x xs = myLast (xs++[x]) == x
Or better:
prop_myLast3 x xs = x `notElem` xs ==> myLast (xs++[x]) == x
hspec is also a testing framework for Haskell, which is inspired by Ruby RSpec. It integrates with QuickCheck, SmallCheck, and HUnit.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With