haskell - 是否有一个实用程序可以轻松地在 Haskell 中编写参数化测试?

标签 haskell testing

一方面,我们有自动测试来检查一个特定的例子。另一方面,我们有基于属性的测试 la QuickCheck,我们提供属性,而框架提供示例,但我们可能必须解释应如何生成示例。

介于这两个极端之间的是编写单个测试或属性并在多个用户提供的示例上运行它的可能性。 Haskell 测试环境中有哪些实用程序可帮助编写此类参数化测试?

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

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

产生这样的输出:

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 =============

Haskell 中有类似的东西吗?

最佳答案

这是 how I do it with HUnit :

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

我简单地使用带有列表 monad 的 do 符号来创建 HUnit 可以执行的测试列表 ([Test])。

通常,我 inline them ,所以它们看起来像这样:

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
  ]

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

关于haskell - 是否有一个实用程序可以轻松地在 Haskell 中编写参数化测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54148654/

相关文章:

java - 如何将测试包添加到现有的 ejb 项目中?

android - Espresso : String in adapterView

java - JUnit 产生奇怪的 AssertionFailedError

haskell - 如何以及何时使用状态仿函数和状态应用?

haskell - 如果代码包含模块定义,为什么我不能用 GHC 编译?

algorithm - 简单的行转置密码

ruby-on-rails - Rails, stripe feature test error - 参数缺失或值为空 : charge

java - 测试 Web 服务消费者

list - 数据类型排序的Haskell列表

haskell - 使用 Parsec 跳过空白行