Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simple haskell unit testing

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?

like image 633
Daniel Huckstep Avatar asked Apr 16 '11 01:04

Daniel Huckstep


2 Answers

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 
like image 156
Ed'ka Avatar answered Sep 21 '22 11:09

Ed'ka


hspec is also a testing framework for Haskell, which is inspired by Ruby RSpec. It integrates with QuickCheck, SmallCheck, and HUnit.

like image 31
stian Avatar answered Sep 23 '22 11:09

stian