如何使用Haskell堆栈项目运行多个测试文件

时间:2017-04-06 19:16:41

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

我想用Stack设置现有的Haskell项目。现有项目在 <% @stud.each do |student_arr|%> <% student_arr.each do |student| %> <li> <%= student.prename + " " + student.lastname + " " + student._format_birthday + " DaZ: " + student.daz.to_s%> (<%= link_to "Details", action: "detail", id: student.id %>) (<%= link_to "Edit", action: "edit", id: student.id %>) </li> <% end %> <% end %> 目录下使用多个文件;这些单独的测试文件默认情况下,Stack(或cabal?)似乎使用单个test进行测试。如何在此项目中继续使用多个文件?

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

2 个答案:

答案 0 :(得分:25)

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

> 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.hsBSpec.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(如果我忘了一个,我最亲切的道歉 - 那些也是我经常使用的那些)。

答案 1 :(得分:1)

这是一个只有堆栈和 HUnit 的解决方案。不反对 hspec、htf、美味等,但同样,如果您已经在使用 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."