在HUnit中对ErrorCall进行Haskell单元测试

时间:2012-11-29 17:20:30

标签: haskell hunit

我有一个功能:

unify :: [Constraint] -> [Substitution]

并且在某些情况下它会使用error函数抛出异常:

error "Circular constraint"

我正在使用Test.HUnit进行单元测试,我想制作一个测试用例,断言在某些输入上抛出这些错误。我找到了this,它提供了一种测试Eq实例的异常的方法,但是error似乎给了an ErrorCall exception,这不是{{1}的实例所以我得到错误:

Eq

如何编写No instance for (Eq ErrorCall) arising from a use of `assertException' 断言已调用TestCase并且(最好)检查邮件?

1 个答案:

答案 0 :(得分:5)

理想情况下,我会将您的功能重构为

unify' :: [Constraint] -> Maybe [Substitution]
unify' = -- your original function, but return Nothing instead of calling error,
         -- and return Just x when your original function would return x

unify = fromMaybe (error "Circular constraint") . unify'

然后我会测试unify'而不是测试unify

如果有多个可能的错误消息,我会像这样重构它:

unify' :: [Constraint] -> Either String [Substitution]
    -- and return Left foo instead of calling error foo

unify = either error id . unify'

(顺便说一句,如果这是针对其他程序员将使用的库,他们中的一些人更愿意调用unify'而不是部分函数unify。)


如果您无法重构代码,我会修改您链接到的代码,将assertException替换为:

assertErrorCall :: String -> IO a -> IO ()
assertErrorCall desiredErrorMessage action
    = handleJust isWanted (const $ return ()) $ do
        action
        assertFailure $ "Expected exception: " ++ desiredErrorMessage
  where isWanted (ErrorCall actualErrorMessage)
            = guard $ actualErrorMessage == desiredErrorMessage