haskell - 是否有一个实用程序可以在 Haskell 中轻松编写参数化测试?
问题描述
一方面,我们有检查一个特定示例的自动化测试。另一方面,我们有基于属性的测试 à 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中有类似的东西吗?
解决方案
这是我使用 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
我只是使用do
带有 list monad 的符号来创建[Test]
HUnit 可以执行的测试列表 ( )。
通常,我将它们内联,使它们看起来像这样:
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
]
我确信还有其他方法可以实现这一目标,但我喜欢这个,因为它不需要任何额外的依赖项;它只是利用了语言的功能。
推荐阅读
- django - 尽管字段具有“空白=真”,但 Django EmbeddedModelField 在执行 PUT 请求时说“此字段可能不是空白”
- vulkan - VkDebugUtilsMessengerEXT 使用的最小 Vulkan 示例不输出任何内容?
- android-instant-apps - libwebsockets 无法在 android 即时应用程序中建立 Web 套接字连接
- javascript - 当父宽度减小时移动内部元素
- mysql - mysql查询回调返回值到变量
- graphviz - 在 Graphviz 中写在边缘箭头上的边缘标签
- javascript - 删除键和退格键事件在 IE 中不起作用
- sql - 计数记录并按小时分组
- javascript - jQuery If else 以错误的顺序应用错误的类
- vb.net - 从数组中选择随机元素并显示在文本框中