尽管有CPP覆盖,但hspec无法导入(私有)代码依赖

时间:2016-01-16 10:43:51

标签: haskell c-preprocessor ghc cabal hspec

我们说我有一个像这样的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无法按预期工作?我该如何解决?

2 个答案:

答案 0 :(得分: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,那么如果您不小心更改它,可能会有一些测试会发现回归。

答案 1 :(得分:0)

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