如何将基于属性的测试用作模糊单元测试

属性测试的优势与应用

Eivind Jahren 在 NDC TechTown 的演讲中强调了属性测试的重要性。他认为属性测试是一种易于使用且高效的工具,具有以下优势:

  • 灵活性强:可以根据需求灵活制定测试要求。
  • 轻量级:足够简单,适合软件开发者在日常工作中进行迭代测试。
  • 减少测试代码:相比传统测试方法,属性测试需要的代码量更少。
  • 重用测试数据生成器:对于复杂结构化数据,重用测试数据生成器比创建新的测试数据更容易。

模糊测试与属性测试的结合

Jahren 提到,模糊测试是一种通过反复向程序提供随机输入来发现程序错误(如内存泄漏、无效操作、崩溃等)的方法。模糊测试可以结合属性测试,作为模糊单元测试的一部分:

属性测试与其他单元测试和集成测试一起编写,并包含一些更重量级的测试,用于模糊测试代码的较大部分。

属性测试的示例

Jahren 以 Python 的排序函数 sorted() 为例,展示了如何使用属性测试库 "hypothesis":

from hypothesis import given
import hypothesis.strategies as st

@given(st.lists(elements=st.integers()))
def test_sorted(list):
    sorted_list = sorted(list)

    assert_is_permutation(list, sorted_list)
    assert_is_ordered(sorted_list)

def assert_is_permutation(list1, list2):
    for element in (list1+list2):
        assert list1.count(element) == list2.count(element) 

def assert_is_ordered(list):
    for i in range(len(sorted)-1):
        assert list[i] <= list[i+1]

在这个例子中,@given 装饰器会默认调用 100 次测试,每次使用随机生成的整数值列表。通过 sorted() 函数对列表进行排序,并验证排序后的列表是输入列表的有序排列。

属性测试库的特点

Jahren 提到,属性测试库通常由两部分组成:一个用于生成所需形状的测试数据的组合库,以及一个将测试数据注入单元测试的测试运行器。常见的功能包括:

  • 缩小:自动简化测试用例以更容易定位问题。
  • 状态测试:支持状态机的测试。
  • 测试数据控制:提供机制来重现和控制测试数据的数量。

Jahren 还推荐了一个 属性测试库列表,其中列出了不同语言的属性测试库及其提供的功能。

属性测试与其他测试方法的比较

与形式验证、其他模糊测试技术和代码检查工具相比,属性测试在需求的制定上更具灵活性,且足够轻量级,适合所有开发者日常使用。Jahren 强调,属性测试的一个即时效果是它能够在代码编写过程中发现更多的错误,因为工具生成的测试数据可能超出开发者的考虑范围。

属性测试的反馈与收获

Jahren 提到,最令人惊讶和一致的反馈是开发者认为使用属性测试非常有趣。测试失败的情况通常很有趣或令人惊讶,而通过测试的代码则更具弹性,这增加了开发者的成就感。

InfoQ 采访总结

在 InfoQ 的采访中,Jahren 进一步解释了属性测试与传统测试方法的对比:

  • 传统测试的局限性:测试数据的生成依赖于测试作者的想象力,可能存在不足。
  • 属性测试的优势:能够生成开发者可能未考虑到的测试数据,从而发现更多错误。

Jahren 还分享了一个关于浮点数计算精度的例子,展示了属性测试在发现复杂问题中的优势。

结论

属性测试是一种强大且灵活的工具,能够帮助开发者在代码编写过程中发现更多错误,减少测试代码量,并提高测试数据的重用性。它的轻量级设计使得所有开发者都能在日常工作中轻松应用,并且开发者普遍认为使用属性测试是一种有趣且有益的经历。

阅读 7
0 条评论