【问题标题】:How to Run Multiple Test Files with Haskell Stack Project如何使用 Haskell Stack 项目运行多个测试文件
【发布时间】:2017-04-06 19:16:40
【问题描述】:

我想用Stack 设置一个现有的 Haskell 项目。现有项目使用test目录下的多个文件;默认情况下,这些单独的测试文件,Stack(或 cabal?)似乎使用单个 test/Spec.hs 进行测试。如何继续在此项目中使用多个文件?

注意:我正在学习 Haskell,这个项目是我从“kata”方法中学习的。因此,测试是孤立的,一次只关注语言的一个方面。

【问题讨论】:

  • 您可以在.cabal 文件中配置堆栈的测试(和其他)行为。寻找测试部分
  • @Lazersmoke 我知道.cabal 文件中有一个部分。您是否有关于如何为多个测试文件进行此配置的示例?我还没有找到一个明确的例子,因此提出了这个问题

标签: unit-testing haskell tdd cabal haskell-stack


【解决方案1】:

这是一个这样的目录结构的设置

> tree                                                                                       
.
├── example.cabal
├── app
│   └── Main.hs
├── ChangeLog.md
├── LICENSE
├── Setup.hs
├── src
│   ├── A
│   │   └── C.hs
│   ├── A.hs
│   └── B.hs
├── stack.yaml
└── tst
    ├── integration
    │   └── Spec.hs
    └── unit
        ├── A
        │   └── CSpec.hs
        ├── ASpec.hs
        ├── BSpec.hs
        └── Spec.hs

您希望有与通常的单元测试分开的集成测试以及与src-文件夹中的每个模块相对应的几个子模块

首先您需要将测试套件添加到您的

example.cabal文件

name:                example
...
-- copyright:
-- category:
build-type:          Simple
extra-source-files:  ChangeLog.md
cabal-version:       >=1.10

executable testmain
  main-is:       Main.hs
  hs-source-dirs: app
  build-depends: base
               , example

library
  exposed-modules:     A.C,A,B
  -- other-modules:
  -- other-extensions:
  build-depends:       base >=4.9 && <4.10
  hs-source-dirs:      src
  default-language:    Haskell2010

test-suite unit-tests
  type:          exitcode-stdio-1.0
  main-is:       Spec.hs
  hs-source-dirs: tst/unit
  build-depends: base
               , example
               , hspec
               , hspec-discover
               , ...

test-suite integration-tests
  type:          exitcode-stdio-1.0
  main-is:       Spec.hs
  hs-source-dirs: tst/integration
  build-depends: base
               , example
               , hspec
               , ...

将以下内容放入您的tst/unit/Spec.hs,它来自hspec-discover,它会发现(因此得名)...Spec.hs 形式的所有模块,并从每个模块中执行spec 函数。

tst/unit/Spec.hs

{-# OPTIONS_GHC -F -pgmF hspec-discover #-}

就这一行

其他测试文件

然后将您的单元测试添加到您的ASpec.hs,将其他单元测试添加到BSpec.hsCSpec.hs 和您的Spec.hs 中的tst/integration 文件夹

module ASpec where

import Test.Hspec
import A

spec :: Spec
spec = do
  describe "Prelude.head" $ do
    it "returns the first element of a list" $ do
      head [23 ..] `shouldBe` (23 :: Int)

    it "returns the first element of an *arbitrary* list" $
      property $ \x xs -> head (x:xs) == (x :: Int)

    it "throws an exception if used with an empty list" $ do
      evaluate (head []) `shouldThrow` anyException

然后你可以编译并运行你的测试

$> stack test
# now all your tests are executed
$> stack test :unit-tests
# now only the unit tests run
$> stack test :integration-tests
# now only the integration tests run

来源

您可以在https://hspec.github.io 找到所有示例,如果您想了解有关 hspec 样式测试的更多信息,我想最好从那里开始。对于堆栈 - 转到 https://haskellstack.org - 那里有一些关于测试/基准测试的信息 - 我的意思是关于运行测试和基准测试。

有关 haskell 中不同的测试风格,请参阅 HUnit、QuickCheck、Smallcheck、doctests(如果我忘记了,最诚挚的歉意 - 这些也是我经常使用的)。

【讨论】:

  • 非常有价值的答案,谢谢。当我尝试使用此设置 cabal testcabal repl spec 时,我得到 -Wmissing-home-modules 错误,因为 hspec-discover 拾取的 ...Spec.hs 文件未在其他模块中列出 - 虽然它确实工作并运行测试。手动添加这些条目会抵消 hspec-discover 的好处。有没有办法避免警告?
  • @DavidWoods 我认为这个警告是最近才出现的,所以在写这个答案时我没有得到它。一种解决方案是在 cabal 文件的 ghc-options 部分中添加标志 -Wno-missing-home-modules
【解决方案2】:

这是一个只有堆栈和 HUnit 的解决方案。没有什么反对 hspec、htf、taste 等的,但同样,即使没有这些,也不需要太多的胶水,如果你已经在使用 HUnit。它不需要编辑 cabal 文件。最初的问题暗示使用 hspec,因此@epsilonhalbe 仍然更接近该标准。

.
├─stack.yaml
├─package.yaml
├─src/
|   ├─A.hs
|   ├─B.hs
|   ├─Main.hs
├─tst/
|   ├─ATest.hs
|   ├─BTest.hs
|   ├─Main.hs

示例package.yaml 文件:

name:                example
version:             0.1.0.0

dependencies:
- HUnit >= 1.6.1.0 && < 2

library:
  source-dirs: src

executables:
  example-exe:
    main:                Main.hs
    source-dirs:         src
    dependencies:
    - example

tests:
  example-test:
    main:                Main.hs
    source-dirs:         tst
    dependencies:
    - example
    - HUnit

在 ATest.hs 和 BTest.hs 中以通常的 HUnit 方式声明名为 huTests 的测试列表,例如,

huTests = ["egTest" ~: "a" ~=? "a"].

然后tst/Main.hs 在一个常见的 HUnit 习语中有胶水(参见例如this answer):

import ATest (huTests)
import BTest (huTests)

import System.Exit
import Test.HUnit

main :: IO ()
main = do
    results <- runTestTT $
                    test (ATest.huTests ++ BTest.huTests)
    if errors results + failures results == 0 then
        putStrLn "Tests passed."
    else
        die "Tests failed."

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-08-19
    • 2015-11-18
    • 2021-02-20
    • 2021-12-08
    • 2021-06-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多