2

我仍然是 Haskell 的初学者。我通过尝试来学得最好,但有时我觉得我错过了一些基本的东西。这是其中之一。

我有一些调用Control.Exception.assert的代码,但没有抛出断言异常。我将此追踪到默认情况下被忽略的断言(这是不寻常的,因为文档建议相反),所以我将其添加到我的package.yaml

library:
  ghc-options:
    - -fno-ignore-asserts

我没有使用-O1or所以我不知道为什么默认行为是忽略-O2,但这不是这个问题的真正含义。-fignore-assertsassert

我想编写一个 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. 根据我的阅读,我可以使用fmapliftM调用非单子函数,例如checkAssert- 但我无法编译:

Couldn't match expected type ‘a10 -> r0’ with actual type ‘Bool’
• In the first argument of ‘liftM’, namely ‘checkAssert’

有人可以解释一下我在哪里出错了吗?

注意:我意识到Test.HUnit.ToolshasassertRaises并且我最初尝试使用它,但Test.Tasty.HUnit由于某种原因不包含此功能。

4

0 回答 0