我希望能够确保函数在接收到无效值时会抛出错误。例如,假设我有一个只返回正数的函数pos:
pos :: Int -> Int
pos x
| x >= 0 = x
| otherwise = error "Invalid Input"
这是一个简单的例子,但我希望你明白这个想法。
我希望能够编写一个期望出现错误并将其视为通过测试的测试用例。例如:
tests = [pos 1 == 1, assertError pos (-1), pos 2 == 2, assertError pos (-2)]
runTests = all (== True) tests
[我的解决方案]
这是我最终根据@ hammar的评论进行的。
instance Eq ErrorCall where
x == y = (show x) == (show y)
assertException :: (Exception e, Eq e) => e -> IO a -> IO ()
assertException ex action =
handleJust isWanted (const $ return ()) $ do
action
assertFailure $ "Expected exception: " ++ show ex
where isWanted = guard . (== ex)
assertError ex f =
TestCase $ assertException (ErrorCall ex) $ evaluate f
tests = TestList [ (pos 0) ~?= 0
, (pos 1) ~?= 1
, assertError "Invalid Input" (pos (-1))
]
main = runTestTT tests
答案 0 :(得分:3)
OP的解决方案定义了assertException
,但testpack中的Test.HUnit.Tools.assertRaises
似乎也可以使用。
我将msg
参数添加到assertError
以匹配assertRaises
的工作方式,并包含选择性导入,因此像我这样的新手可以了解常用内容的导入位置。
import Control.Exception (ErrorCall(ErrorCall), evaluate)
import Test.HUnit.Base ((~?=), Test(TestCase, TestList))
import Test.HUnit.Text (runTestTT)
import Test.HUnit.Tools (assertRaises)
pos :: Int -> Int
pos x
| x >= 0 = x
| otherwise = error "Invalid Input"
instance Eq ErrorCall where
x == y = (show x) == (show y)
assertError msg ex f =
TestCase $ assertRaises msg (ErrorCall ex) $ evaluate f
tests = TestList [
(pos 0) ~?= 0
, (pos 1) ~?= 1
, assertError "Negative argument raises an error" "Invalid Input" (pos (-1))
]
main = runTestTT tests
答案 1 :(得分:0)
有几种方法可以处理Haskell中的错误。以下是概述:http://www.randomhacks.net/articles/2007/03/10/haskell-8-ways-to-report-errors
<强> [编辑] 强>
第一个例子说明了如何捕捉错误,例如
half :: Int -> Int
half x = if even x then x `div` 2 else error "odd"
main = do catch (print $ half 23) (\err -> print err)
那就是说,这种错误处理更适合IO
的东西,像你这样的纯代码也许,或者类似的东西通常是更好的选择。它可以像......一样简单。
pos :: Int -> Maybe Int
pos x
| x >= 0 = Just x
| otherwise = Nothing
tests = [pos 1 == Just 1
,pos (-1) == Nothing
,pos 2 == Just 2
,pos (-2) == Nothing
]
main = print $ and tests
...如果您不需要错误类型。