尽管 CPP 覆盖,hspec 仍无法导入(私有)代码依赖项
hspec failing to import (private) code dependency despite CPP override
假设我有一个这样的 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 没有按预期工作?我该如何解决?
问题只是语法错误。 #ifdef
错了,#ifndef
对了
Why is my CPP not working as expected?
Two-step 建筑。由于您的测试依赖于库,因此它首先构建。该库没有设置任何 CPP 选项,因此 alphabet
不会导出。
构建测试时,您的库已经编译,alphabet
不会导出。这是关注点分离。
How can I fix it?
有几个技巧可以使用 "hidden"(例如 non-exported)函数。首先,您可以将它们全部放入 .Internal
模块中。这样,想要使用隐藏位的用户可以很容易地做到这一点,但临时用户手头没有太多工具。
处理这个问题的另一种方法是删除测试中的依赖项,而是将 src
目录添加到测试中:
hs-source-dirs: tests, src
然而,这也意味着您必须重建整个库以进行测试,但它将启用 CPP。
第三种选择是不测试 alphabet
,而是测试依赖它的导出函数的可观察行为。所以不是测试 alphabet
,而是测试 filterAlpha
:
filterAlpha :: String -> String
filterAlpha = filter (`elem` alphabet)
无论如何你都要测试filterAlpha
。如果有很多函数使用 alphabet
,如果您不小心更改它,您可能会有一些测试会注意到回归。
假设我有一个这样的 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 没有按预期工作?我该如何解决?
问题只是语法错误。 #ifdef
错了,#ifndef
对了
Why is my CPP not working as expected?
Two-step 建筑。由于您的测试依赖于库,因此它首先构建。该库没有设置任何 CPP 选项,因此 alphabet
不会导出。
构建测试时,您的库已经编译,alphabet
不会导出。这是关注点分离。
How can I fix it?
有几个技巧可以使用 "hidden"(例如 non-exported)函数。首先,您可以将它们全部放入 .Internal
模块中。这样,想要使用隐藏位的用户可以很容易地做到这一点,但临时用户手头没有太多工具。
处理这个问题的另一种方法是删除测试中的依赖项,而是将 src
目录添加到测试中:
hs-source-dirs: tests, src
然而,这也意味着您必须重建整个库以进行测试,但它将启用 CPP。
第三种选择是不测试 alphabet
,而是测试依赖它的导出函数的可观察行为。所以不是测试 alphabet
,而是测试 filterAlpha
:
filterAlpha :: String -> String
filterAlpha = filter (`elem` alphabet)
无论如何你都要测试filterAlpha
。如果有很多函数使用 alphabet
,如果您不小心更改它,您可能会有一些测试会注意到回归。