我仍然是 Haskell 的初学者。我通过尝试来学得最好,但有时我觉得我错过了一些基本的东西。这是其中之一。
我有一些调用Control.Exception.assert
的代码,但没有抛出断言异常。我将此追踪到默认情况下被忽略的断言(这是不寻常的,因为文档建议相反),所以我将其添加到我的package.yaml
:
library:
ghc-options:
- -fno-ignore-asserts
我没有使用-O1
or所以我不知道为什么默认行为是忽略-O2
,但这不是这个问题的真正含义。-fignore-asserts
assert
我想编写一个 Hspec 单元测试来检查这种行为(同时也是一个了解 Hspec 的机会)。
在我的Lib
模块中:
-- Lib.hs
module Lib (checkAssert) where
import Control.Exception
checkAssert :: Bool
checkAssert = assert (1 == 2) False
这个模块是用-fno-ignore-asserts
.
在我的Spec.hs
(我实际上是在使用 Tasty 来主持测试):
import Test.Tasty
import Test.Tasty.Hspec
import Lib
import GHC.IO.Unsafe (unsafePerformIO)
import qualified Control.Exception (assert, AssertionFailed)
import Control.Monad
assertionException :: Selector Control.Exception.AssertionFailed
assertionException = const True
-- Hspec tests
spec_assertRaises :: Spec
spec_assertRaises = do
it "assert" $ (liftM checkAssert) `shouldThrow` assertionException
unitTests :: TestTree
unitTests = testGroup "Lib Unit Tests"
[ -- add Hspec tests to Tasty TestTree
unsafePerformIO (testSpec "spec" spec_assertRaises)
]
main :: IO()
main = defaultMain unitTests
此测试模块未使用-fno-ignore-asserts
. 我认为这没关系,因为它实际上并没有调用assert
自己,它只是调用模块中的函数checkAssert
,该函数是使用该标志编译的。Lib
我遇到的问题实际上与如何从 Monad 调用非单子函数有关,例如Spec
. 根据我的阅读,我可以使用fmap
或liftM
调用非单子函数,例如checkAssert
- 但我无法编译:
Couldn't match expected type ‘a10 -> r0’ with actual type ‘Bool’
• In the first argument of ‘liftM’, namely ‘checkAssert’
有人可以解释一下我在哪里出错了吗?
注意:我意识到Test.HUnit.Tools
hasassertRaises
并且我最初尝试使用它,但Test.Tasty.HUnit
由于某种原因不包含此功能。