【问题标题】:Haskell QuickCheck Test not running properly when run with Cabal与 Cabal 一起运行时,Haskell QuickCheck 测试无法正常运行
【发布时间】:2015-04-24 07:09:38
【问题描述】:

我正在开发的 Cabal 包有些地方没有意义,我将问题归结为以下示例:

我有以下简单的测试模块:

module Main where
import Test.QuickCheck (quickCheck)
main = quickCheck False

和以下Cabal文件在同一目录下:

name:                project
version:             0.1.0.0
cabal-version:       >= 1.10
build-type:          Simple

executable project
  main-is:             Main.hs
  build-depends:       base, QuickCheck
  default-language:    Haskell2010

test-suite project-test
  type:                exitcode-stdio-1.0
  main-is:             Main.hs
  build-depends:       base, QuickCheck
  default-language:    Haskell2010

目录中唯一的其他文件是 dist(由 Cabal 在构建时创建)和 cabal 沙箱文件。可执行文件和测试套件都引用 Main.hs,因此我希望在运行“cabal run”时获得与运行“cabal test”时相同的测试结果。然而,显然情况并非如此。

“阴谋集团”给出:

Preprocessing executable 'project' for project-0.1.0.0...
Running project...
*** Failed! Falsifiable (after 1 test):

这是有道理的,因为属性测试“quickCheck False”应该会失败。正如预期的那样,这与我在 ghci 中运行 main 时得到的结果相同。

然而,“cabal test”给出:

Test suite project-test: RUNNING...
Test suite project-test: PASS
Test suite logged to: dist/test/project-0.1.0.0-project-test.log
1 of 1 test suites (1 of 1 test cases) passed.

为什么“cabal test”通过了测试用例,而“cabal run”却按预期失败了?

【问题讨论】:

  • 我认为第一个问题是您编写“退出代码”的方式仍然可以-tbh:正确知道为什么您看不到quickCheck的输出(可能是被cabal test 抑制,因为它返回ok)。我通常使用hspec,效果很好——也许你会试一试
  • 好吧,稍后我通过简单的网络搜索为您找到了可能的解决方案:cabal-test-quickcheck

标签: haskell cabal quickcheck


【解决方案1】:

quickCheck 不退出程序,因此,它不设置退出代码。毕竟,你可以有几个quickCheck 测试,它们应该相互独立:

main = do
    quickCheck prop1 -- should this exit if the test fails?
    quickCheck prop2 -- should this exit if the test fails?
    quickCheck prop3 -- should this exit if the test fails?

但是,如果您 a) 在其中一个测试未通过时立即退出,或者 b) 记住单个测试是否未通过,然后使用正确的代码退出,则可以轻松解决此问题。

仅使用 QuickCheck,不使用其他库

测试失败就退出

为此,您只需使用quickCheckResult,您可以通过Test.QuickCheck.Test 使用isSuccess 进行检查。如果您想使用当前的quickCheck 定义,您可以使用合格的包含来将默认实现与您的特殊实现交换:

import           Control.Monad          (when)    
import           System.Exit            (exitFailure)
import           Test.QuickCheck hiding (quickCheck, quickCheckWith)
import qualified Test.QuickCheck.Test as Q

quickCheckWith :: Testable prop => Args -> prop -> IO ()
quickCheckWith args p = do
      success <- fmap Q.isSuccess $ quickCheckWithResult args p 
      when (not success) $ exitFailure -- exit if the result is a failure

quickCheck :: Testable prop => prop -> IO ()
quickCheck p = quickCheckWith stdArgs p

不过,您可能应该使用其他名称,尤其是在其他人从事同一个项目的情况下。 checkOrExit 是合理的。

返回失败代码但运行所有测试

这本质上是相同的,但运行所有测试。您必须再次使用quickCheckResultquickCheckWithResult

import           Control.Monad          (when)    
import           System.Exit            (exitFailure)
import           Test.QuickCheck        (quickCheckResult)
import           Test.QuickCheck.Test   (isSuccess)

main :: IO ()
main = do
  let tests = [ quickCheckResult prop1
              , quickCheckResult prop2
              , quickCheckResult prop3
              , quickCheckResult prop4
              ]
  success <- fmap (all isSuccess) . sequence $ tests
  when (not success) $ exitFailure

使用额外的测试库

虽然quickCheck 非常适合进行属性检查,但它并没有提供完整的测试框架。这就是其他成熟的框架,如tastyhspec 派上用场的地方。他们可以获取Testable a 并相应地检查 QuickCheck 的结果。一个使用hspec的例子:

module Main where
import Test.Hspec
import Test.QuickCheck (property)

main = hspec $ do
  describe "<method you would like to test>" $ 
    it "<property/assumption you would like to test>" $ 
       property $ False -- quickCheck

这给出了(更详细的)输出

<method you would like to test>
  - <property/assumption you would like to test> FAILED [1]

1) <method you would like to test> <property/assumption you would like to test>
Falsifiable (after 1 test):
   [remark: the used values would be here, but `False` is a boolean]

Randomized with seed 2077617428

Finished in 0.0019 seconds
1 example, 1 failure

此外,它会以错误代码退出,因此您的cabal test 将正确识别此失败的测试。这些测试框架还具有其他功能,超出了此答案的范围。

TL;DR

QuickCheck 不会退出您的程序,但 Cabal只检查退出代码以确定测试是否通过。由于任何定期结束的 Haskell 程序都返回零(也就是没有错误),因此您要么需要使用 exitFailure(或类似的东西),要么需要在幕后使用 exitFailure 的框架。

请注意,这只适用于 type: exitcode-stdio-1.0 的测试。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 2019-09-06
    • 1970-01-01
    相关资源
    最近更新 更多