[Haskell-cafe] HUnit/cabal integration

Simon Hengel sol at typeful.net
Thu Jul 5 16:17:33 CEST 2012


> First: the web page I cite above describes the interface that the test
> binary must support to work with cabal, specifically w.r.t. the binary's
> exit code.  "Your test suites likely already fit this model.  However, if
> you are using an old version of QuickCheck or HUnit, your executable may
> not be returning the correct error code."
> 
> This seems to me to suggest that recent versions of HUnit automatically
> take care of generating the exit code, but I've found that I have to
> examine HUnit's results and synthesize the exit code manually, as in the
> driver program below.  (I'm running HUnit 1.2.4.2, but the interface for
> 1.2.4.3 doesn't appear to differ on this point.)  Am I misinterpreting the
> wiki page, or am I missing something in HUnit's API that generates the exit
> code automatically?

AFAIK, you have to do it explicitly.  But you can shorten it to
something like this:

    when (errors c /= 0 || failures c /= 0)
      exitFailure

Personally I'd use some test framework that is build on top of HUnit and
QuickCheck.  My weapon of choice is Hspec [1], but there are other
options.

> Second: Am I specifying the Build-Depends correctly for the Test-Suite?
> Specifically: do I need to state a dependency on the library defined in the
> same package, or does it pick that up automatically?  Further, foo-tests
> doesn't use parsec directly.  Is the transitive dependency automatically
> provided for me, or do I need to list it explicitly as below?

You only have to add dependencies on what you actually use, so if you
depend on your library and only use stuff from your library, you do not
need to depend on parsec.

On a broader scope, you have two options, either

(a) Depend on your library in your Cabal test section.

or

(b) Include the source files of your library in your Cabal test section.

Whether you want (a) or (b) depends on the circumstances.  Here is a
(possibly not complete) list of differences:


 - (a) Is suitable when you only want to test the public interface of
   your library, but it does not allow you to test stuff that is not
   exposed.  In contrast, (b) allows you to test stuff that is not
   exposed.

 - (a) usually gives you a short test section in your Cabal file (and is
   more DRY). (b) requires you to repeat all dependencies, options, etc.
   of your library section in your test section.

 - Compilation is slower with (b), because the source files of your
   library are compiled twice.

 - (b) even works in the rare case, when your test framework depends on
   your library (e.g. if you use HUnit to test a dependency of HUnit).

I'm assuming here, that your library sources and test sources live in
different directory hierarchies, and I'm not sure what the exact
behavior is, if they don't!

Let's look at an example.  If your library sources are in '.' and your
test sources are in 'test' option (a) looks like so:

  test-suite foo-tests
    type:
        exitcode-stdio-1.0
    main-is:
        foo-tests.hs
    hs-source-dirs:
        test
    build-depends:
        base >= 4.3.1.0 && < 5
      , foo                    -- depend on your library
      , HUnit >= 1.2.4.2

And option (b) looks like so:

  test-suite foo-tests
    type:
        exitcode-stdio-1.0
    main-is:
        foo-tests.hs
    hs-source-dirs:
        .                      -- include the sources of your library
      , test
    build-depends:
        base >= 4.3.1.0 && < 5
      , parsec >= 3.1.2        -- inculde the depencencies of your library
      , HUnit >= 1.2.4.2

Hope that helps.  Feel free to ask, if anything is unclear.

Cheers,
Simon

[1] http://hspec.github.com/



More information about the Haskell-Cafe mailing list