1

假设我有一个像这样的 src 文件:

{-# LANGUAGE CPP #-}
module Alphabet (
#ifdef TEST
  alphabet
#endif
) where
  alphabet :: [Char]
  alphabet = "abcdefghijklmnopqrstuvwxyz"

像这样的.cabal文件:

name:                Alphabet
version:             0.1.0.0
library
  build-depends:       base >=4.8 && <4.9, containers >=0.5 && <0.6, split >=0.2 && <0.3
  hs-source-dirs:      src
  Exposed-modules:     Alphabet
  default-language:    Haskell2010
test-suite alphabet-test
  ghc-options:         -Wall -Werror
  cpp-options:         -DTEST
  default-extensions:  OverloadedStrings
  type:                exitcode-stdio-1.0
  main-is:             Spec.hs
  hs-source-dirs:      tests
  build-depends:       Alphabet, base >= 4.8 && < 4.9, containers >= 0.5 && <0.6, split >= 0.2 && < 0.3, hspec, QuickCheck
  default-language:    Haskell2010

像这样的主测试文件:

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

和一个测试文件,如:

module AphabetSpec (spec) where

  import Test.Hspec
  import Alphabet (alphabet)

  spec :: Spec
  spec = do
    describe "Alphabet.alphabet" $ do
      it "returns the alphabet" $ do
        alphabet `shouldBe` "abcdefghijklmnopqrstuvwxyz"

now running `cabal test`:
cabal test
Preprocessing library Alphabet-0.1.0.0...
In-place registering Alphabet-0.1.0.0...
Preprocessing test suite 'alphabet-test' for Alphabet-0.1.0.0...
[1 of 1] Compiling Main             ( tests/AlphabetSpec.hs, dist/build/alphabet-test/alphabet-test-tmp/AlphabetSpec.o )

tests/AlphabetSpec.hs:4:27:
Module ‘Alphabet’ does not export ‘alphabet’

为什么我的 CPP 没有按预期工作?我该如何解决?

4

2 回答 2

3

为什么我的 CPP 没有按预期工作?

两步建设。由于您的测试依赖于库,因此首先构建它。该库没有设置任何 CPP 选项,因此alphabet不会被导出。

构建测试时,您的库已经编译,并且alphabet不会被导出。这是关注点分离。

我该如何解决?

使用“隐藏”(例如非导出)函数有几个技巧。一方面,您可以将它们全部放入一个.Internal模块中。这样,想要使用隐藏位的用户可以很容易地做到这一点,但临时用户手头没有太多工具。

处理此问题的另一种方法是删除测试中的依赖项,而是将src目录添加到测试中:

 hs-source-dirs:      tests, src

但是,这也意味着您必须重建整个库以进行测试,但它将启用使用 CPP。

第三种选择是不测试alphabet,而是依赖于它的导出函数的可观察行为。因此alphabet,您可以测试,而不是测试filterAlpha

filterAlpha :: String -> String
filterAlpha = filter (`elem` alphabet)

filterAlpha无论如何,您必须进行测试。如果有许多函数使用alphabet,很可能你会有一些测试,如果你不小心改变它会注意到回归。

于 2016-01-16T13:17:16.883 回答
0

问题是一个简单的语法错误。#ifdef是错的,#ifndef是对的

于 2016-01-16T11:11:54.890 回答