假设等同于QuickCheck频率发生器?

时间:2019-03-23 18:12:31

标签: python haskell quickcheck property-based-testing python-hypothesis

作为一个学习项目,我正在将一些Haskell代码(我不熟悉)翻译成Python(我很了解)...

我正在翻译的Haskell库具有使用基于QuickCheck属性的测试的测试。在Python方面,我将Hypothesis用作基于属性的测试库。

Haskell测试使用了一个类似于以下内容的辅助函数:

mkIndent' :: String -> Int -> Gen String
mkIndent' val size = concat <$> sequence [indent, sym, trailing]
  where
    whitespace_char = elements " \t"
    trailing = listOf whitespace_char
    indent = frequency [(5, vectorOf size whitespace_char), (1, listOf whitespace_char)]
    sym = return val

我的问题特别是关于此帮助程序中的frequency生成器。 http://hackage.haskell.org/package/QuickCheck-2.12.6.1/docs/Test-QuickCheck-Gen.html#v:frequency

我理解它的意思是大部分时间它会返回vectorOf whitespace_char与预期的size,但是五分之一会返回listOf whitespace_char可以是任何长度,包括零。

在库的上下文中,不遵守size的缩进将为被测函数建模错误的输入数据。所以我看到了偶尔产生这种输入的意义。

我目前不明白的是为什么5:1的比例支持有效的输入?我希望基于属性的测试框架能够生成各种有效和无效的输入。现在,我认为这有点像优化,因此它不会花费大部分时间来生成无效的示例吗?

我的问题的第二部分是如何将其转化为假设。 AFAICT假设没有frequency生成器的等效项。

我想知道我是否应该尝试根据现有的假设策略自己构建frequency策略,还是这个惯用语本身不值得翻译,我应该让该框架生成同样有效和无效的示例吗? >

我目前拥有的是:

from hypothesis import strategies as st

@st.composite
def make_indent_(draw, val, size):
    """
    Indent `val` by `size` using either space or tab.
    Will sometimes randomly ignore `size` param.
    """
    whitespace_char = st.text(' \t', min_size=1, max_size=1)
    trailing = draw(st.text(draw(whitespace_char)))
    indent = draw(st.one_of(
        st.text(draw(whitespace_char), min_size=size, max_size=size),
        st.text(draw(whitespace_char)),
    ))
    return ''.join([indent, val, trailing])

如果我在shell中生成一些示例,这似乎完全按照我的想法做。

但这是我第一次使用假设或基于属性的测试,我想知道是否通过用简单的frequency代替one_of分布来失去一些至关重要的东西?

1 个答案:

答案 0 :(得分:3)

据我所知,您已经正确理解了在此使用frequency的目的。它用于允许偶尔使用错误大小的缩进,而不是(1)仅生成正确大小的缩进,而这些缩进绝不会测试坏的缩进大小;或(2)生成大小随机的缩进,可以一遍又一遍地测试坏的缩进,但仅生成一部分具有良好的缩进的情况以测试代码的其他方面。

现在,好的缩进大小(可能是不好的缩进大小)的5:1比例可能是相当任意的,并且很难知道是1:1还是10:1会是更好的选择,而看不到所测试内容的详细信息。

幸运的是,就将其移植到hypothesis而言,对Have a Strategy that does not uniformly choose between different strategies的回答包括已删除的评论:

  

假设实际上并不支持特定于用户的概率-我们从统一分布开始,但根据观察到的输入的覆盖范围对其进行偏倚。 [...] –扎克·哈特菲尔德-多兹18年4月15日,下午3:43

这表明“假设”包在使用one_of来增加覆盖率时会自动调整权重,这意味着它可能会在您的make_indent_实现中以正确的大小自动增加大小,从而使其成为frequency的自动版本。