Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Haskell中运行所有测试和测试用例组合_Haskell_Testing - Fatal编程技术网

在Haskell中运行所有测试和测试用例组合

在Haskell中运行所有测试和测试用例组合,haskell,testing,Haskell,Testing,我的目标是能够定义一组测试方法和一组测试用例(输入/输出数据),然后执行它们的所有组合。我们的目标是避免在同一个函数有3个不同的实现和4个该函数应该满足的测试用例时,一遍又一遍地重新编写相同的代码。天真的方法需要我编写12行代码: testMethod1测试用例1 testMethod1测试用例2 测试方法3测试用例4 我有一种直觉,Haskell应该以某种方式提供一种抽象这种模式的方法。我目前想到的最好的东西是这段代码: import Control.Applicative data Te

我的目标是能够定义一组测试方法和一组测试用例(输入/输出数据),然后执行它们的所有组合。我们的目标是避免在同一个函数有3个不同的实现和4个该函数应该满足的测试用例时,一遍又一遍地重新编写相同的代码。天真的方法需要我编写12行代码:

testMethod1测试用例1

testMethod1测试用例2

测试方法3测试用例4

我有一种直觉,Haskell应该以某种方式提供一种抽象这种模式的方法。我目前想到的最好的东西是这段代码:

import Control.Applicative

data TestMethod a = TM a
data TestData inp res = TD inp res

runMetod (TM m) (TD x res) = m x == res

runAllMethods ((m, inp):xs) = show (runMetod m inp) ++ "\n" ++ runAllMethods xs
runAllMethods _          = ""

head1 = head
head2 (x:xs) = x
testMethods = [TM head1, TM head2]
testData = [TD [1,2,3] 1, TD [4,5,6] 4]

combos = (,) <$> testMethods <*> testData

main = putStrLn $ runAllMethods combos
然而,这只适用于相同类型的列表,即使head函数是列表类型不可知的。我想收集任何列表的测试数据,如下所示:

import Control.Applicative

data TestMethod a = TM a
data TestData inp res = TD inp res

runMetod (TM m) (TD x res) = m x == res

runAllMethods ((m, inp):xs) = show (runMetod m inp) ++ "\n" ++ runAllMethods xs
runAllMethods _          = ""

head1 = head
head2 (x:xs) = x
testMethods = [TM head1, TM head2]
testData = [TD [1,2,3] 1, TD ['a','b','c'] 'a']

combos = (,) <$> testMethods <*> testData

main = putStrLn $ runAllMethods combos

是否有可能以某种方式实现此测试功能X测试用例交叉测试?

您应该真正使用QuickCheck或类似工具,就像hnefatl所说的那样。 但为了好玩,让我们把你的想法付诸实施吧

所以你有一个多态函数和许多不同类型的测试用例。唯一重要的是,您可以应用每种类型的函数

让我们看看你的函数。它的类型是
[a]->a
。您的测试数据应该是什么样子?它应该由一个列表和一个值组成,并且应该支持相等比较。这就引出了如下定义:

{-# LANGUAGE GADTs #-}
{-# LANGUAGE ImpredicativeTypes #-}
{-# LANGUAGE RankNTypes #-}

data TestData where
  TestData :: Eq a => [a] -> a -> TestData
您需要启用
GADTs
语言扩展才能工作。为了让下面的工作正常进行,您需要这两个扩展(尽管可以使用类型类对整个过程进行泛化以避免这种情况,只需查看QuickCheck)

现在测试它:

head1 = head
head2 (a : as) = a

test :: (forall a . [a] -> a) -> TestData -> Bool
test f (TestData as a) = f as == a

testAll :: [(forall a . [a] -> a)] -> [TestData] -> Bool
testAll fs testDatas = and $ test <$> fs <*> testDatas

main = putStrLn $ if testAll [head1, head2] [TestData "Foo" 'F', TestData [1..] 1]
  then "Success!"
  else "Oh noez!"
head1=头
总目2(a:as)=a
测试::(对于所有a.[a]->a)->TestData->Bool
测试f(测试数据作为a)=f作为==a
testAll::[(对于所有a.[a]->a]->[TestData]->Bool
testAll fs testDatas=和$test fs testDatas
main=putStrLn$if testAll[head1,head2][TestData“Foo”'F',TestData[1..]1]
然后是“成功!”
否则“哦,诺兹!”

我将让您对不同的测试函数类型进行概括。

似乎您应该切换到类似或(或类似组合框架)的东西。在
头的特定情况下::[a]->a
函数,注意在整数上测试就足够了。事实上,如果它对整数有效,根据与其多态类型相关联的自由定理,它必须对所有其他类型有效。在这里,参数化让我们避免在无限多的类型上进行测试。这种情况经常发生在与列表相关的函数上。在我看来,这个问题很好地描述了这个问题,并显示了研究的努力。有什么问题吗?谢谢你的主意,但我没能让它发挥作用。编译器抱怨:无法将类型“a1”与“a”匹配“a1”是由构造函数为TestData::forall a的模式绑定的刚性类型变量。等式a=>[a]->a->TestData,在“test”的等式中,我假设这是因为TestData不包含任何关于它实际包含的类型的信息,然后编译器假设a的函数内测试::([a]->a)->TestData->Bool可能与它的TestData输入参数中的不同。@PetrasPurlys,这将教会我在不事先编译的情况下上传代码。查看更新的代码。谢谢!总而言之,这是一个很酷的解决方案。但是(或如果)与TestData有什么关系呢?@PetrasPurlys,
forall a。[a] ->a
头的类型
。将[a]更改为b以获得通用版本是不够的,是吗?我希望你能给我一些提示,我一个人做这件事可能太难了。
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ImpredicativeTypes #-}
{-# LANGUAGE RankNTypes #-}

data TestData where
  TestData :: Eq a => [a] -> a -> TestData
head1 = head
head2 (a : as) = a

test :: (forall a . [a] -> a) -> TestData -> Bool
test f (TestData as a) = f as == a

testAll :: [(forall a . [a] -> a)] -> [TestData] -> Bool
testAll fs testDatas = and $ test <$> fs <*> testDatas

main = putStrLn $ if testAll [head1, head2] [TestData "Foo" 'F', TestData [1..] 1]
  then "Success!"
  else "Oh noez!"