我正在使用hspec
进行一些基本测试。
我有一个argsParser
函数,该函数给出了一些参数,返回或更确切地说打印了它们的有效性。
argsParser :: [String] -> IO ()
argsParser args | null args = print "no args provided"
| not $ null args && length args < 2 = print "no file name provided"
| length args > 2 == print "too many arguments"
| otherwise = goAhead args
问题是我不确定如何将IO ()
与另一个IO ()
进行比较。
我认为liftIO
可能会有所帮助,但
x <- liftIO $ print "something"
y <- liftIO $ print "anything"
我明白了
x == y = True
我怀疑是因为两者都是actions
。
答案 0 :(得分:12)
您无法将IO操作与其他操作进行比较。可计算性理论指出,无法确定两个IO值是否相等。因此,Haskell中没有实例Eq (IO a)
。
充其量,您可以尝试运行这两个动作,从外部观察它们的效果,然后比较它们的效果-这并不总是可行的(例如,如果一个动作是一个无限循环,则该动作需要用户输入)但它可能足够接近。可以通过将操作作为子流程运行,重定向其标准输出/错误来实现此检查。
(为什么要比较IO操作?这很不寻常)
答案 1 :(得分:3)
首先,将argsParser
简化为 just 检查数字的内容
args;还没有做任何IO。
import System.IO
data ArgsError = NoArgs | NoFilename | TooManyArgs
instance Show ArgsError where
show NoArgs = "no args specified"
show NoFilename = "no file name specified"
show TooManyArgs = "too many arguments"
validateArgs :: [String] -> Either ArgsError [String]
validateArgs args | null args = Left NoArgs
| length args < 2 = Left NoFilename
| length args > 2 = Left TooManyArgs
| otherwise = Right args
goAhead :: [String] -> IO ()
-- as before
现在,您只需为Either ArgsError [String]
值提供一个 handler ,这是either :: (a -> c) -> (b -> c) -> Either a b -> c
的简单应用。
main = do
args <- getArgs
either (hPrint stderr) goAhead (validatedArgs args)
您现在可以轻松测试validateArgs
,并且可以说either (hPrint stderr) goAhead
不需要 进行测试。