Unit testing 用Haskell编写不同类型的测试用例
我制作了一个创建“类似列表”序列的库,其中实现了许多Prelude样式的函数。我想为此编写一些测试用例,以确保我的库生成正确的输出,我认为最简单的方法是编写一些函数,将结果转换为列表,并将它们与Prelude结果进行比较。假设我们有:Unit testing 用Haskell编写不同类型的测试用例,unit-testing,haskell,testing,Unit Testing,Haskell,Testing,我制作了一个创建“类似列表”序列的库,其中实现了许多Prelude样式的函数。我想为此编写一些测试用例,以确保我的库生成正确的输出,我认为最简单的方法是编写一些函数,将结果转换为列表,并将它们与Prelude结果进行比较。假设我们有: import qualified MyLibrary as ML import qualified Prelude as P 例如,我可能需要以下测试用例: P.take 5 (P.enumFrom 1) == toList (ML.take 5 (ML.enu
import qualified MyLibrary as ML
import qualified Prelude as P
例如,我可能需要以下测试用例:
P.take 5 (P.enumFrom 1) == toList (ML.take 5 (ML.enumFrom 1))
请注意,ML.enumFrom
不输出列表,而是输出自己的数据类型
上述方法很好,但请注意我是如何“重复我自己”(TM)。我必须确保左侧和右侧是相同的,否则我的测试用例是错误的
有没有一种很好的方法来编写这样的测试用例,这样我就不必重复我自己了?第一个问题是
p.take
和ML.take
等,它们看起来很相似——事实上它们是完全不相关的函数,编译器对它们的常见行为一无所知。因此,正如@jd823592所建议的,我们需要用一个typeclass对它们进行分组(我使用了一个简单的newtype
包装器,这样示例就可以编译了):
然后,我们将尝试使用类定义中现在统一的函数定义一些测试。它们可能只生成任何类型的序列
,然后我们将强制它们生成显式类型
test1 = doTest (take 5 $ enumFrom 1) -- the part in brackets is polymorphic
doTest :: (Eq a, Sequence s) => s a -> Bool
doTest test = ???
现在第二个问题是,我们将多态函数作为参数传递,然后需要使用不同的类型参数对其进行实例化([a]
在本例中是MySeq a
)。在standard Haskell 2010中,这是不可能的,但我们可以利用:
{-#语言类型}
多斯特:对于所有a。等式a=>(对于所有序列s=>sa)->Bool
doTest test=(test`asTypeOf`dummy1)=toList(test`asTypeOf`dummy2),其中
dummy1::等式a=>[a]
dummy1=未定义
dummy2::Eq a=>MySeq a
dummy2=未定义
这个解决方案有点笨拙,但仍然有效。请随时改进。当你的测试定义为“重复自己”时,我不认为你真的是在“重复自己”为了比较两种机制。理想情况下,所有测试都采用一个参数来确定要使用哪个函数,这样我就可以有一个
doTest
函数,类似于doTest test=test True==toList(test False)
之类的函数,但是我还没有找到一种不让类型检查器讨厌我的方法。@Clinton:我认为如果不实例化一个普通的类
,或者不可能使用模板haskell(我没有经验),你就无法做到这一点
test1 = doTest (take 5 $ enumFrom 1) -- the part in brackets is polymorphic
doTest :: (Eq a, Sequence s) => s a -> Bool
doTest test = ???
{-# LANGUAGE Rank2Types #-}
<...>
doTest :: forall a . Eq a => (forall s . Sequence s => s a) -> Bool
doTest test = (test `asTypeOf` dummy1) == toList (test `asTypeOf` dummy2) where
dummy1 :: Eq a => [a]
dummy1 = undefined
dummy2 :: Eq a => MySeq a
dummy2 = undefined