【问题标题】:How to test with hspec whether the readerError function was executed如何用 hspec 测试 readerError 函数是否被执行
【发布时间】:2016-06-15 03:43:11
【问题描述】:

我是 Haskell 的新手。

我编写了以下代码,它将解析发送到脚本的参数;

module Billing.Options
  (
      GlobalOpts(..)
    , globalOptsParser
    , parseDb
  ) where

import Options.Applicative
import Options.Applicative.Simple
import Options.Applicative.Types
import System.FilePath.Posix
import Text.Regex.PCRE

-- ------------------------------------------------------------

data GlobalOpts = GlobalOpts
  {
    optDb          :: String,
    optSql         :: String
  } deriving Show

-- ------------------------------------------------------------

globalOptsParser :: Parser GlobalOpts
globalOptsParser = GlobalOpts
  <$> option (parseDb =<< readerAsk)
    (   long "db"
    <>  short 'd'
    <>  metavar "<DB name>"
    <>  help "dmt | report"
    )
  <*> option parseSql
    (   long "sql"
    <>  metavar "<SQL SELECT statement>"
    <>  help "sql select statement to use in order to generate JSON config file"
    )
-- ------------------------------------------------------------

matches :: String -> String -> Bool
matches = (=~)

-- ------------------------------------------------------------

parseDb :: String -> ReadM String
parseDb val = do
    if not (elem val ["dmt", "report"])
        then readerError $ "Unknown DB, '" ++ val ++ "'"
        else return val

-- ------------------------------------------------------------

parseSql :: ReadM String
parseSql = do
    val <- readerAsk
    if not (val `matches` "(?i)select .+ from .+")
        then readerError $ "Please provide a valid SQL SELECT statement"
        else return val

-- [EOF]

我想用 hspec 测试上面的“parseDb”函数。我想确保在指定未知数据库时会抛出“readerError”。因此我想测试函数调用 解析数据库“未知” 生成一个“readerError”调用,据我说应该抛出异常。

我尝试了 hspec shouldThrow 函数,但它不起作用。似乎没有抛出异常。 readerError 的返回类型是“ReadM a”。在花了几天时间阅读 monads 和 reader monads 之后,我仍然被卡住(和困惑)并且不知道如何测试它,甚至不知道是否可以测试它。谷歌搜索时找不到任何相关示例。

【问题讨论】:

  • 用另一个例子更新了我的答案。

标签: haskell testing hspec


【解决方案1】:

以下是一些相关的类型信号:

parseDb :: String -> ReadM String

-- from Options.Applicative.Internal

runReadM :: MonadP m => ReadM a -> String -> m a
runP :: P a -> ParserPrefs -> (Either ParseError a, Context)

runReadMrunP 的文档:(link)

ParserPrefs 只是一个简单的数据结构。

这个类型检查:

 import Options.Applicative.Types
 import Options.Applicative.Internal

 parseDb :: String -> ReadM String
 parseDb val = do
     if not (elem val ["dmt", "report"])
         then readerError $ "Unknown DB, '" ++ val ++ "'"
         else return val

 foo :: (Either ParseError String, Context)     -- might be [Context] now
 foo =   runP (runReadM (parseDb "foo") "asd") opts
   where opts = ParserPrefs "suffix" False False False 80

评估fst foo 返回:

*Main> fst foo
Left (ErrorMsg "Unknown DB, 'foo'")

更新

这里是如何测试ParserglobalOptsParser

import Options.Applicative.Common (runParser)
import Options.Applicative.Internal (runP)

bar = let mp = runParser AllowOpts globalOptsParser ["asd"]
          opts = ParserPrefs "suffix" False False False 80
      in fst $ runP mp opts

["asd"] 是要测试的命令行参数。

检查 ParserPrefs 是否是您想要的 - 它们会影响选项处理。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-08-07
    • 1970-01-01
    • 2019-11-26
    • 1970-01-01
    • 1970-01-01
    • 2016-11-16
    • 1970-01-01
    • 2018-06-13
    相关资源
    最近更新 更多