如何在基于属性的测试中提出属性

How to come up with properties in propety based testing

这个问题适用于任何特定的编程语言。

让我们假设我有一个将数据结构转换为十六进制字符串的函数。

func toHex(input: data) => string

假设我现在想使用基于 属性 的测试来对此进行测试。我如何着手提出测试所依据的属性?

我在 属性 周围看到的所有基于测试的示例都假定非常简单的数学关系。诸如测试反转列表或字符串是否是另一个字符串的子字符串之类的事情。

但是对于上面的 toHex 函数,我想不出任何可行的方法来提出 属性 因为它看起来唯一的关系是一些数据被转换为十六进制细绳。除了实现查找另一个执行类似操作的库并将其用于测试中的断言的转换功能之外。但是这样做会导致使用基于 属性 的测试失败。

关于如何处理基于 属性 的测试以及如何在这种 toHex 函数的情况下提出要在测试中使用的属性的任何想法或建议?

信不信由你,这实际上是一个相当常见的案例,基于 属性 的测试非常有用 - 还有一个:

将数据结构转换为字符串(或 JSON、XML 或类似的东西)的函数本身很少有用。通常,您需要它的对应物:反序列化器或解析器。

当你有这样一对函数时,你可以写一种属性,即Scott Wlaschin calls There and back again:你生成测试数据作为序列化器的输入,然后调用序列化器(toHex),然后用序列化数据再次调用 parser/deserializer (fromHex?)。那么 属性 就是 fromHex 的输出应该等于 toHex.

的输入

这是我编写 serializer/parser 对时首选的测试策略。你可以在我的文章 Types + Properties = Software: other properties.

中看到一个最小的例子

有时,根据所解决的问题,来来回回 属性 可以作为部分 描述序列化器的,当与其他属性结合时。这是 FizzBu​​zz 套路的部分描述的 Haskell QuickCheck 示例:

testProperty "Numbers round-trip" $ \ (i :: Int) ->
  let range = [i..i+2]
 
      actual = fizzBuzz <$> range
 
      numbers = catMaybes $ readMaybe <$> actual
  in counterexample
      (show range ++ "->" ++ show actual) $
      all (`elem` range) numbers

示例取自我的文章Property-based testing is not the same as partition testing

FizzBu​​zz 是一个类似于 toHex 的问题。输入是 'data structure' ((Integral a, Show a)),输出是 String(虽然不是十六进制编码)。

解析器通常是 return MaybeEither 值的部分函数,​​因此 'round-trip' 断言通常需要验证 Just input === output 之类的东西。