使用 stack 和 hpack 运行自定义测试

问题描述

我正在尝试编写自己的测试框架,但我什至无法开始。这是我的目录结构:

 $ tree
.
├── prj1
│   ├── package.yaml
│   ├── src
│   │   └── Module.hs
│   └── test-dir
│       └── TheTest.hs
└── stack.yaml

每个文件是:

stack.yaml

resolver: lts-16.11
packages:
  - prj1

package.yaml

name: prj1
version: 0.1
maintainer: fakedrake
category: Test

library:
  source-dirs: src
  exposed-modules: []
  dependencies:
      - base

tests:
  prj1-tests:
    main: TheTest.hs
    source-dirs: test-dir
    dependencies:
      - base

TheTest.hs

module TheTest () where


main :: IO ()
main = putStrLn "Test passes!"

Module.hs

module Module () where

但是当我运行 stack test 时我得到

$ stack test
prj1> configure (lib + test)
Configuring prj1-0.1...
prj1> build (lib + test)
Preprocessing library for prj1-0.1..
Building library for prj1-0.1..
[1 of 2] Compiling Module
[2 of 2] Compiling Paths_prj1
Preprocessing test suite 'prj1-tests' for prj1-0.1..
Building test suite 'prj1-tests' for prj1-0.1..
[1 of 2] Compiling Paths_prj1
[2 of 2] Compiling TheTest

<no location info>: error:
    output was redirected with -o,but no output will be generated
because there is no Main module.

--  While building package prj1-0.1 using:
      /my/home/.stack/setup-exe-cache/x86_64-osx/Cabal-simple_mPHDZzAJ_3.0.1.0_ghc-8.8.3 --builddir=.stack-work/dist/x86_64-osx/Cabal-3.0.1.0 build lib:prj1 test:prj1-tests --ghc-options ""
    Process exited with code: ExitFailure 1
Progress 1/2

解决方法

基于 HPack / Stack 的项目的约定是测试的主要入口点位于文件 test/Spec.hs

因此,只需将您的模块 TheTest.hs 重命名为 Spec.hs,并在 main: Spec.hstests: 部分设置 package.yaml,一切都应该没问题。>

您还可以生成一个基于 HPack/Stack 的最小项目脚手架,包括以 stack new prj1 为起点的测试套件。

Spec.hs 作为主要入口点的好处是它允许自动查找 测试用例。

要启用此功能,只需在 Spec.hs 中放置一行:

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

这个 pragma 会找到所有遵循命名约定的模块

*Spec.hs

然后你可以有像ReverseSpec.hs这样的单独的测试模块:

module ReverseSpec where

import           Test.Hspec

-- `main` is here so that this module can be run from GHCi on its own.  It is
-- not needed for automatic spec discovery.
main :: IO ()
main = hspec spec

-- this is the actual entry point for tests
spec :: Spec
spec = do
  describe "reverse" $ do
    it "is inverse to itself" $
      property $ \str -> (reverse . reverse) str `shouldBe` (id str :: String)

如果您真的想推出自己的测试框架,您可以按如下方式编辑您的文件 TheTest.hs

  1. 没有模块子句:
-- module TheTest () where

main :: IO ()
main = putStrLn "Test passes!"
  1. 或使用修改后的模块子句:
module Main where

main :: IO ()
main = putStrLn "Test passes!"

这适用于 cabal teststack test