这是我最近用于libraries 之一的.cabal 文件的片段。
...
Library
Build-depends: base >= 4 && < 5, bytestring, directory, filepath, hslogger,
SHA, zlib
Ghc-options: -Wall
Exposed-modules: Ltc.Store
Test-suite reference
Hs-Source-Dirs: Test, .
Main-Is: ReferenceProps.hs
Type: exitcode-stdio-1.0
Build-Depends: base >= 4 && < 5, bytestring, directory, filepath, hslogger,
SHA, zlib
Ghc-Options: -Wall
Build-Depends: test-framework, test-framework-hunit, test-framework-quickcheck2,
HUnit, QuickCheck
我们可以看到 cabal 文件定义了一个库和一个测试套件。该库定义了它导出的模块、它所依赖的包,并设置了一些自定义 GHC 选项。
我们可以轻松地构建和打包库以进行分发:
% cabal configure
% cabal build
% cabal sdist
测试套件看起来很像库:首先,它与库具有相同的依赖项(参见第一行 Build-Depends),然后添加了一些额外的测试依赖项(参见第二行 Build-Depends )。这里的测试套件是 HUnit 和 QuickCheck 测试的组合,它使用Test-Framework 作为运行器。 test 正确的是Test/ReferenceProps.hs。这是一个exitcode-stdio 类型测试。这意味着如果 ReferenceProps 以代码 0 退出,cabal 会说测试通过。否则,它会说测试失败。
测试套件看起来像this(但是,在这里,我们将使用一些简单的测试来进行列表反转):
import Data.Monoid
import Test.Framework
import Test.Framework.Providers.HUnit
import Test.Framework.Providers.QuickCheck2
import Test.HUnit
import Test.QuickCheck
main :: IO ()
main = defaultMainWithOpts
[ testCase "rev" testRev
, testProperty "listRevRevId" propListRevRevId
] mempty
testRev :: Assertion
testRev = reverse [1, 2, 3] @?= [3, 2, 1]
propListRevRevId :: [Int] -> Property
propListRevRevId xs = not (null xs) ==> reverse (reverse xs) == xs
main 只是一个安全带。您还可以通过替换mempty 为test-framework 设置各种选项。函数testRev是HUnit测试,propListRevRevId是QuickCheck测试;请参阅 relevant docs 了解如何编写这些内容。
最后,我们可以运行测试了:
% cabal configure --enable-tests
% cabal test