我正在学习haskell,并且是一个好的开发人员,请在我走时编写单元测试。我实施了各种排序算法和相应的测试。但是,我觉得单独的测试是冗余的,因为输入和输出没有变化,只有用于对输入进行排序的算法。是否有一种方法可以在其他各种单元测试框架中创建数据驱动的测试或数据表?
module RecursionSpec (main, spec) where
import Test.Hspec
import Recursion
main :: IO ()
main = hspec spec
spec :: Spec
spec = do
let input = [3, 1, 5, 2, 4]
output = [1, 2, 3, 4, 5]
describe "bubblesort" $ do
it ("sorts " ++ show input) $ do
bubblesort input `shouldBe` output
describe "mergesort" $ do
it ("sorts " ++ show input) $ do
mergesort input `shouldBe` output
describe "quicksort" $ do
it ("sorts " ++ show input) $ do
quicksort input `shouldBe` output
另外,我收到以下警告,我想了解和消除。
warning: [-Wtype-defaults]
• Defaulting the following constraints to type ‘Integer’
(Show a0)
arising from a use of ‘show’ at test/RecursionSpec.hs:14:21-30
(Eq a0)
arising from a use of ‘shouldBe’ at test/RecursionSpec.hs:15:7-40
(Ord a0)
arising from a use of ‘bubblesort’ at test/RecursionSpec.hs:15:7-22
(Num a0)
arising from the literal ‘1’ at test/RecursionSpec.hs:12:17
(Num a0)
arising from the literal ‘3’ at test/RecursionSpec.hs:11:16
• In the second argument of ‘(++)’, namely ‘show input’
In the first argument of ‘it’, namely ‘("sorts " ++ show input)’
In the expression: it ("sorts " ++ show input)
您可以定义一个高阶函数:
describeSort :: Ord a => String -> ([a] -> [a]) -> [a] -> [a] -> SpecWith b
describeSort sortName sorter input output =
describe sortName $ do
it ("sorts " ++ show input) $ do
sorter input `shouldBe` output
它不是数据驱动的,但基本上是在这种情况下删除样板(我无法验证语法是完全正确的,没有HSPEC安装)。
然后您可以将测试定义为:
spec :: Spec
spec = do
let input = [3, 1, 5, 2, 4]
output = [1, 2, 3, 4, 5]
describeSort "bubblesort" bubblesort input output
describeSort "mergesort" mergeSort input output
describeSort "quicksort" quickSort input output
专门针对Haskell的更多数据驱动(属性测试)测试框架是QuickCheck
。它允许您定义函数遵守的"属性",然后可以生成数据来测试这些数据。例如,对排序功能的快速测试可以写为:
quickCheck (xl -> bubblesort xl == sort xl)
其中sort
是Data.List
版本,而bubblesort
是您正在测试的实现。然后,QuickCheck将生成适合约束的100个列表(必须是Ord
值列表),并报告遇到的任何错误。
您可以通过明确说明input
和output
S的类型来解决该警告:
let input = [3, 1, 5, 2, 4] :: [Integer]
output = [1, 2, 3, 4, 5] :: [Integer]