首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Hunit测试(异常)

Hunit测试(异常)
EN

Stack Overflow用户
提问于 2015-12-09 13:14:13
回答 1查看 742关注 0票数 2

我正在编写一个解析xml的程序。

我采用了使用MonadThrow来处理解析中的错误的方法,但是现在当测试失败时--无法找到如何测试它们的方法。这让我不确定这种方法是否正确。

首先,这里是一个完整的(不起作用的)示例。

exception.hs

代码语言:javascript
复制
{-# 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

代码语言:javascript
复制
[...]
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
               ,       text

TL;DR

我不知道在上一次单元测试中使用什么代替undefined,以及在这种情况下使用异常的方法是否正确。

我想到了几种选择:

  • 使用(either displayException show $ parseTxt parser failTxt) @?= undefined仍然失败,并且不会产生Left值。
  • 在我看来,使用assertFail违背了拥有Either SomeException TestElement的目的。
  • 我可以使用一个自定义的异常类型来匹配它,但我是否可以使用“失败”抛出我自己类型的错误?

我认为我困惑的原因之一是我不知道什么时候会抛出错误(我认为懒惰的评估会在与错误相匹配时抛出错误--这显然是错误的)。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-12-10 12:17:38

多亏了@user2407038,我才能解决这个问题:

为异常定义新的数据类型

代码语言:javascript
复制
data ParseException = TagMismatch String deriving (Typeable, Eq, Show)

然后调整导入和下列功能

代码语言:javascript
复制
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")
              . fromException

Note1:deriving Eq只对单元测试中的@?=操作是必需的,对于代码的生产版本可以省略。

Note2:对resourcet的直接依赖也可以由exceptions代替,前者只是再导出。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34179759

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档