[英]Haskell unit testing
我是haskell的新手,正在进行单元测试,但我发现生态系统非常混乱。 我对HTF和HUnit之间的关系感到困惑。
在一些示例中,我看到您设置测试用例,将它们导出到测试列表中,然后使用runTestsTT
在ghci中运行( 如此HUnit示例 )。
在其他示例中,您创建一个绑定到cabal文件的测试运行器,该文件使用一些预处理器魔法来查找您的测试,就像在这个git示例中一样 。 似乎HTF测试需要以test_
为前缀,否则它们不会运行? 我很难找到任何相关的文档,我只是注意到每个人都有的模式。
无论如何,有人可以帮我解决这个问题吗? 什么被认为是在Haskell做事的标准方式? 什么是最佳做法? 什么是最容易设置和维护?
通常,任何重要的Haskell项目都与Cabal一起运行。 这需要建立,分发,文档(在haddock的帮助下)和测试。
标准方法是将测试放在test
目录中,然后在.cabal
文件中设置测试套件。 这在用户手册中有详细说明。 这是我的一个项目的测试套件的样子
Test-Suite test-melody
type: exitcode-stdio-1.0
main-is: Main.hs
hs-source-dirs: test
build-depends: base >=4.6 && <4.7,
test-framework,
test-framework-hunit,
HUnit,
containers == 0.5.*
然后在文件test/Main.hs
import Test.HUnit
import Test.Framework
import Test.Framework.Providers.HUnit
import Data.Monoid
import Control.Monad
import Utils
pushTest :: Assertion
pushTest = [NumLit 1] ^? push (NumLit 1)
pushPopTest :: Assertion
pushPopTest = [] ^? (push (NumLit 0) >> void pop)
main :: IO ()
main = defaultMainWithOpts
[testCase "push" pushTest
,testCase "push-pop" pushPopTest]
mempty
Utils
定义了一些比HUnit更好的接口。
对于轻量级测试,我强烈建议您使用QuickCheck 。 它允许您编写短属性并通过一系列随机输入对其进行测试。 例如:
-- Tests.hs
import Test.QuickCheck
prop_reverseReverse :: [Int] -> Bool
prop_reverseReverse xs = reverse (reverse xs) == xs
然后
$ ghci Tests.hs
> import Test.QuickCheck
> quickCheck prop_reverseReverse
.... Passed Tests (100/100)
我也是新手哈斯克勒,我发现这个介绍真有帮助:“ HUnit入门 ”。 总而言之,我将在这里放置一个没有.cabal
项目文件的HUnit用法的简单测试示例:
我们假设我们有模块SafePrelude.hs
:
module SafePrelude where
safeHead :: [a] -> Maybe a
safeHead [] = Nothing
safeHead (x:_) = Just x
我们可以将测试放入TestSafePrelude.hs
,如下所示:
module TestSafePrelude where
import Test.HUnit
import SafePrelude
testSafeHeadForEmptyList :: Test
testSafeHeadForEmptyList =
TestCase $ assertEqual "Should return Nothing for empty list"
Nothing (safeHead ([]::[Int]))
testSafeHeadForNonEmptyList :: Test
testSafeHeadForNonEmptyList =
TestCase $ assertEqual "Should return (Just head) for non empty list" (Just 1)
(safeHead ([1]::[Int]))
main :: IO Counts
main = runTestTT $ TestList [testSafeHeadForEmptyList, testSafeHeadForNonEmptyList]
现在使用ghc
运行测试很容易:
runghc TestSafePrelude.hs
或hugs
-在这种情况下TestSafePrelude.hs
已重命名为Main.hs
(据我所熟悉的拥抱)(不要忘记更改模块头太):
runhugs Main.hs
或任何其他haskell
编译器;-)
当然在HUnit
有更多,所以我真的建议阅读建议的教程和库用户指南 。
你已经得到了大部分问题的答案,但你也问过HTF,以及它是如何工作的。
HTF是一个专为单元测试而设计的框架 - 它向后兼容HUnit(它集成并包装它以提供额外的功能) - 以及基于属性的测试 - 它与quickcheck集成。 它使用预处理器来定位测试,这样您就不必手动构建列表。 使用编译指示将预处理器添加到测试源文件中:
{-# OPTIONS_GHC -F -pgmF htfpp #-}
(或者,我猜你可以在你的cabal文件中为你的ghc-options
属性添加相同的选项,但我从来没有尝试过,所以不知道它是否有用)。
预处理器扫描模块以test_xxxx
名为test_xxxx
或prop_xxxx
顶级函数,并将它们添加到模块的测试列表中。 您可以直接使用此列表,方法是在模块中放置一个main
函数并运行它们( main = htfMain htf_thisModuleTests
)或从模块中导出它们,并为多个模块提供主要测试程序,这些模块通过测试导入模块并运行所有模块他们:
import {-@ HTF_TESTS @-} ModuleA
import {-@ HTF_TESTS @-} ModuleB
main :: IO ()
main = htfMain htf_importedTests
该程序可以使用@jozefg描述的技术与cabal集成,或者加载到ghci并以交互方式运行(尽管不在Windows上 - 有关详细信息,请参阅https://github.com/skogsbaer/HTF/issues/60 )。
Tasty是另一种提供集成不同类型测试的方法。 它没有像HTF这样的预处理器,但有一个使用Template Haskell执行类似功能的模块。 与HTF一样,它也依赖于命名约定来识别您的测试(在这种情况下, case_xxxx
而不是test_xxxx
)。 除了HUnit和QuickCheck测试之外,它还具有用于处理许多其他测试类型的模块。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.