我正在编写一个解析xml的程序。
我采用了使用MonadThrow来处理解析中的错误的方法,但是现在当测试失败时--无法找到如何测试它们的方法。这让我不确定这种方法是否正确。
首先,这里是一个完整的(不起作用的)示例。
exception.hs
{-# LANGUAGE OverloadedStrings #-}
import Test.Tasty
import Test.Tasty.HUnit
import Control.Exception (SomeException, displayException)
import Control.Monad (unless)
import Control.Monad.Trans.Resource (MonadThrow)
import Data.Function (on)
import Text.XML (Element, parseText, def, documentRoot, elementName)
import Data.Text (Text)
import Data.Text.Lazy (fromStrict)
data TestElement = TestElement deriving (Show, Eq)
main :: IO ()
main = defaultMain unitTests
unitTests :: TestTree
unitTests = testGroup "Unit tests"
[ testCase "parseTxt parser goodTxt1 == Right TestElement " $
parseTxt parser goodTxt1 @?= Right TestElement
, testCase "parseTxt parser goodTxt2 == Right TestElement " $
parseTxt parser goodTxt2 @?= Right TestElement
, testCase "parseTxt parser failTxt == Left \"ElementName does not match TestElement\"" $
parseTxt parser failTxt @?= undefined
--hunit
]
parseTxt :: (Element -> Either SomeException a) -> Text -> Either SomeException a
parseTxt parser inText = documentRoot <$> (parseText def $ fromStrict inText) >>=
parser
parser :: MonadThrow m => Element -> m TestElement
parser elmt =
do unless (elementName elmt == "TestElement")
$ fail "ElementName does not match TestElement"
{-here usually some more complicated attribute/subnode parsing happens-}
return TestElement
failTxt :: Text
failTxt = "<ToastElement></ToastElement>"
goodTxt1 :: Text
goodTxt1 = "<TestElement />"
goodTxt2 :: Text
goodTxt2 = "<TestElement></TestElement>"
instance Eq SomeException where
(==) = (==) `on` displayException它需要exception.cabal
[...]
executable exception
hs-source-dirs: src
main-is: Main.hs
default-language: Haskell2010
build-depends: base >= 4.7 && < 5
, xml-conduit
, exceptions
, resourcet
, tasty
, tasty-hunit
, textTL;DR
我不知道在上一次单元测试中使用什么代替undefined,以及在这种情况下使用异常的方法是否正确。
我想到了几种选择:
(either displayException show $ parseTxt parser failTxt) @?= undefined仍然失败,并且不会产生Left值。assertFail违背了拥有Either SomeException TestElement的目的。我认为我困惑的原因之一是我不知道什么时候会抛出错误(我认为懒惰的评估会在与错误相匹配时抛出错误--这显然是错误的)。
发布于 2015-12-10 12:17:38
多亏了@user2407038,我才能解决这个问题:
为异常定义新的数据类型
data ParseException = TagMismatch String deriving (Typeable, Eq, Show)然后调整导入和下列功能
parseTxt :: Exception e => (Element -> Either e a) -> Text -> Either SomeException a
parseTxt parser inText = documentRoot <$> (parseText def $ fromStrict inText) >>=
(first toException . parser)
first :: (a -> c) -> Either a b -> Either c b
first f (Left l) = Left (f l)
first _ (Right r) = Right r
parser :: MonadThrow m => Element -> m TestElement
parser elmt =
do unless (elementName elmt == "TestElement")
$ throwM $ TagMismatch "TestElement"
return TestElement
unitTests :: TestTree
unitTests = testGroup "Unit tests"
[ {-...-}
testCase "parseTxt parser failTxt == fail" $
(first aux $ parseTxt parser failTxt) @?= Left $ TagMismatch "TestElement"
]
where aux = fromMaybe (error "converting from SomeException failed")
. fromExceptionNote1:deriving Eq只对单元测试中的@?=操作是必需的,对于代码的生产版本可以省略。
Note2:对resourcet的直接依赖也可以由exceptions代替,前者只是再导出。
https://stackoverflow.com/questions/34179759
复制相似问题