Cabal Test Suite Best Practice

October 7, 2014

I’ve beem coming across a lot of great best practices ever since I’ve started my first Haskell gig. I’m going to try to post more generally useful things I learn them.

Best Practice: Depend on Your Library in Test Suite

99% of the time when I’m creating a library, I’m going to have the test suite in the same cabal file. Recent versions of cabal are smart and will resolve dependencies within the file first. This is much better than the alternative, which is to copy and maintain the dependencies for the library in the test suite. That becomes a huge maintenance liability for no reason.

Say you have a directory structure like

mypkg
├── src
│   └── MyPkg.hs
└── test
    └── src
        └── MyPkgTests.hs

where your library source is in src and your test source is in test/src. You would then create a cabal file that looked something like:

name: mypkg
-- snip
library
  hs-source-dirs: src

  build-depends:
       specific-package >= 1.1 && < 1.2
       -- snip

test-suite test
  type: exitcode-stdio-1.0
  main-is: Main.hs
  hs-source-dirs:
    test/src

  build-depends:
       mypkg
    ,  specific-package
    -- snip

A few things to note:

  • I nail down dependency versions to my liking in the library section.
  • The test section depends on mypkg and is not explicit about dependencies that will be dragged in by mypkg. You actually don’t even need to include these unless you directly use code from these dependencies in your tests
  • Last, and most importantly do not put src in the hs-source-dirs of the test suite. If you do, this trick won’t work. Only put your test source dir in this section.

For the longest time I couldn’t figure out how to do this and ended up with really verbose and hard to maintain cabal files. I knew other people did it this way but I never picked up on the hs-source-dirs clause being the deciding factor until someone on #haskell pointed it out to me.