unit-testing - 在 Haskell 中为不同类型编写测试用例

标签 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.enumFrom 1))

注意 ML.enumFrom 不输出列表,它输出它自己的数据类型。

上面的工作正常,但请注意我是如何“重复自己”(TM)。我必须确保左侧和右侧相同,否则我的测试用例是错误的。

有没有一种好的方法可以编写这样的测试用例,这样我就不必重复自己了?

最佳答案

第一个问题是P.takeML.take等,只是看起来很像——实际上它们是完全不相关的函数,编译器不知道关于他们的共同行为的任何事情。因此,正如 @jd823592 所建议的,我们需要将它们与类型类分组(我使用了一个简单的 newtype 包装器,因此该示例是可编译的):

import Prelude hiding (take, enumFrom)
import qualified Prelude as P (take, enumFrom)

newtype MySeq a = MySeq [a]

class Sequence s where
    take :: Int -> s a -> s a
    enumFrom :: Enum a => a -> s a
    toList :: s a -> [a]

instance Sequence MySeq where
    take n (MySeq xs) = MySeq (P.take n xs)
    enumFrom n = MySeq (P.enumFrom n)
    toList (MySeq xs) = xs

instance Sequence [] where
    take = P.take
    enumFrom = P.enumFrom
    toList = id

然后我们将尝试使用类定义中现在统一的函数来定义一些测试。它们可能只生成任何类型的 Sequence,然后我们将强制它们生成显式类型。

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 来实例化它案件)。在标准的 Haskell 2010 中这是不可能的,但我们可以利用 Rank2 (or RankN) extension :

{-# 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

这个解决方案有点笨拙,但仍然有效。请随时改进。

关于unit-testing - 在 Haskell 中为不同类型编写测试用例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42346429/

相关文章:

java - ProducerTemplate 在单元测试中用于在 new JndiContext 中构造 bean 时为 null

django - 为 Django 为 TDD 设置适当的测试

ruby-on-rails-3 - 使用 Rails Logger 在生产模式下创建日志的问题

haskell - 在 Haskell 中将负基二进制转换为十进制 : "Instances of .. required"

haskell - 代表多个失败案例但只有一个成功案例的惯用类型是什么?

unit-testing - 单元测试的值(value)是否随着单元测试的复杂性而降低?

Python如何在另一个函数中模拟一个函数

android - 100% 的单元测试代码覆盖率——如何用 'defensive' 编码实现?

javascript - 如何为 jquery 调用 `$(some)` 创建 spy ?

php - 如何在 Haskell 或 Python 中翻译这个数学公式? (已用 PHP 翻译)