Unit testing for exceptions

385 Views Asked by At

Can I write a test case with Test.HUnit that checks whether a call throws an exception?

I only care whether it throws any error, regardless of what message it prints.

2

There are 2 best solutions below

3
Chris Martin On

This isn't specific to HUnit, but you can write a function to check whether an IO value throws:

λ> :set -XScopedTypeVariables
λ> import Control.Exception
λ> import Data.Functor
λ> import System.Environment

λ> throws io = catch (io $> False) $ \(e :: SomeException) -> pure True
throws :: IO a -> IO Bool

λ> sequence $ throws <$> [ getEnv "HOME", getEnv "whatever", error "a" ]
[False,True,True]
2
Alec On

If by an "exception" you mean Exception and it is being thrown in some IO code, then you can use catch or catches. However, if you mean catching things like error "Something bad happened" in pure code, you are out of luck. If you are willing to do the handling in IO, you have more options:

ghci> import Control.Exception
ghci> catch (error "Eek") (\(ErrorCallWithLocation msg _) -> putStrLn msg) 
Eek

From the Haskell 2010 report section 3:

Errors during expression evaluation, denoted by ⊥ (“bottom”), are indistinguishable by a Haskell program from non-termination.

Here is another way to think about it: notice that the moment we try to evaluate a value that is ⊥ (like error "Help!") depends not on when this value was created but only when it was first needed (since Haskell is non-strict). A mechanism to catch this sort of error would then break referential transparency.