首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Haskell中有方便编写参数化测试的实用工具吗?

在Haskell中有方便编写参数化测试的实用工具吗?
EN

Stack Overflow用户
提问于 2019-01-11 14:38:12
回答 2查看 97关注 0票数 3

一方面,我们有自动测试,检查一个特定的例子。另一方面,我们有基于属性的QuickCheck测试,在这里我们提供属性,而框架提供示例,但是我们可能需要解释如何生成示例。

在这两个极端之间,存在着编写单个测试或属性并在多个用户提供的示例上运行它的可能性。Haskell测试领域中有哪些实用工具可以帮助编写这样的参数化测试?

作为一个具体的例子,下面是如何在Python的pytest中这样做的。我想检查len函数是否为各种输入提供了正确的输出。这可以通过编写单个测试来完成,该测试可以检查某个输入的长度是否符合测试人员的期望,并将测试参数化为输入示例和相应的预期结果。

代码语言:javascript
复制
from pytest import mark

param = mark.parametrize

@param('input, expected',
       ((''  ,    0),
        ('a' ,    1),
        ('b' ,    1),
        ('ab',    2),
        ('xx',    3), # deliberate mistake
        ('xyz',   3),
        ('aaabc', 5)
       ))
def test_len(input, expected):
    assert len(input) == expected

会产生这样的结果:

代码语言:javascript
复制
len_test.py::test_len[-0] PASSED                      [ 14%]
len_test.py::test_len[a-1] PASSED                     [ 28%]
len_test.py::test_len[b-1] PASSED                     [ 42%]
len_test.py::test_len[ab-2] PASSED                    [ 57%]
len_test.py::test_len[xx-3] FAILED                    [ 71%]  (appears red)
len_test.py::test_len[xyz-3] PASSED                   [ 85%]
len_test.py::test_len[aaabc-5] PASSED                 [100%]

========================= FAILURES ==========================
______________________ test_len[xx-3] _______________________
len_test.py:15: in test_len
    assert len(input) == expected
E   AssertionError: assert 2 == 3
E    +  where 2 = len('xx')
============ 1 failed, 6 passed in 0.04 seconds =============

哈斯克尔有类似的地方吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-01-11 15:00:59

这是我是如何用HUnit做的

代码语言:javascript
复制
adjustToBusinessHoursReturnsCorrectResult :: [Test]
adjustToBusinessHoursReturnsCorrectResult = do
  (dt, expected) <-
    [
      (zt (2017, 10, 2) (6, 59,  4) 0, zt (2017, 10, 2) (9,  0,  0) 0),
      (zt (2017, 10, 2) (9, 42, 41) 0, zt (2017, 10, 2) (9, 42, 41) 0),
      (zt (2017, 10, 2) (19, 1, 32) 0, zt (2017, 10, 3) (9,  0,  0) 0)
    ]
  let actual = adjustToBusinessHours dt
  return $ ZT expected ~=? ZT actual

我只需在list monad中使用do符号来创建HUnit可以执行的测试列表([Test])。

通常情况下,我是将它们内联,因此它们看起来像这样:

代码语言:javascript
复制
main :: IO ()
main = defaultMain $ hUnitTestToTests $ TestList [
  "adjustToBusinessHours returns correct result" ~: do
    (dt, expected) <-
      [
        (zt (2017, 10, 2) (6, 59,  4) 0, zt (2017, 10, 2) (9,  0,  0) 0),
        (zt (2017, 10, 2) (9, 42, 41) 0, zt (2017, 10, 2) (9, 42, 41) 0),
        (zt (2017, 10, 2) (19, 1, 32) 0, zt (2017, 10, 3) (9,  0,  0) 0)
      ]
    let actual = adjustToBusinessHours dt
    return $ ZT expected ~=? ZT actual

  ,
  "Composed adjust returns correct result" ~: do
    (dt, expected) <-
      [
        (zt (2017, 1, 31) ( 7, 45, 55)   2 , zt (2017, 2, 28) ( 7,  0,  0) 0),
        (zt (2017, 2,  6) (10,  3,  2)   1 , zt (2017, 3,  6) ( 9,  3,  2) 0),
        (zt (2017, 2,  9) ( 4, 20,  0)   0 , zt (2017, 3,  9) ( 9,  0,  0) 0),
        (zt (2017, 2, 12) (16,  2, 11)   0 , zt (2017, 3, 10) (16,  2, 11) 0),
        (zt (2017, 3, 14) (13, 48, 29) (-1), zt (2017, 4, 13) (14, 48, 29) 0)
      ]
    let adjustments =
          reverse [adjustToNextMonth, adjustToBusinessHours, adjustToDutchBankDay, adjustToUtc]
    let adjust = appEndo $ mconcat $ Endo <$> adjustments

    let actual = adjust dt

    return $ ZT expected ~=? ZT actual
  ]

我确信实现这个目标还有其他方法,但我喜欢这个方法,因为它不需要任何额外的依赖;它只是利用了语言的功能。

票数 5
EN

Stack Overflow用户

发布于 2019-01-12 09:47:25

请记住,QuickCheck属性(通常)只是一个函数。我们可以使用QuickCheck为其提供参数,但我们也可以轻松地自己提供它们。

代码语言:javascript
复制
prop_foo :: Foo -> Bar -> Bool

prop1 = prop_foo (Foo 6) (Bar 9)
prop2 = prop_foo (Foo 9) (Bar 2)
...

另外,QuickCheck允许提供一个自定义生成器,因此您可以控制测试数据的随机分布,但我确信您也可以使用它以完全非随机的方式生成数据。

然后是HUnit,我非常肯定您可以在测试数据之上fmap测试子例程来生成一组测试用例。实际上,我有时将它用于测试不太适合随机测试的解析器。我编写了一个函数,它接受一个输入字符串和一个预期的解析树,然后构造一个以输入字符串命名的HUnit测试用例,该测试用例在该字符串上运行解析器,并断言输出与给定的期望匹配。

真的,我想有几种方法可以做到这一点。

(你知道SmallCheck吗?它与QuickCheck做的事情本质上是一样的,但是系统地生成输入,而不是随机生成输入。因此,它将尝试所有给定大小的可能输入,然后向上移动到下一个大小。可能不适合您的用例,但值得了解。)

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54148654

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档