Generally, any significant Haskell project is run with Cabal. This takes care of building, distribution, documentation (with the help of haddock), and testing.
The standard approach is to put your tests in the test
directory and then set up a test suite in your .cabal
file. This is detailed in the user manual. Here’s what the test suite for one of my projects looks like
Test-Suite test-melody
type: exitcode-stdio-1.0
main-is: Main.hs
hs-source-dirs: test
build-depends: base >=4.6 && <4.7,
test-framework,
test-framework-hunit,
HUnit,
containers == 0.5.*
Then in the file test/Main.hs
import Test.HUnit
import Test.Framework
import Test.Framework.Providers.HUnit
import Data.Monoid
import Control.Monad
import Utils
pushTest :: Assertion
pushTest = [NumLit 1] ^? push (NumLit 1)
pushPopTest :: Assertion
pushPopTest = [] ^? (push (NumLit 0) >> void pop)
main :: IO ()
main = defaultMainWithOpts
[testCase "push" pushTest
,testCase "push-pop" pushPopTest]
mempty
Where Utils
defines some nicer interfaces over HUnit.
For lighter-weight testing, I strongly recommend you use QuickCheck. It lets you write short properties and test them over a series of random inputs. For example:
-- Tests.hs
import Test.QuickCheck
prop_reverseReverse :: [Int] -> Bool
prop_reverseReverse xs = reverse (reverse xs) == xs
And then
$ ghci Tests.hs
> import Test.QuickCheck
> quickCheck prop_reverseReverse
.... Passed Tests (100/100)