使用 PyHamcrest 执行健壮的单元测试
创始人
2024-03-02 01:48:53
0

使用此框架编写断言,提高开发测试的准确性。

测试金字塔的底部是单元测试。单元测试每次只测试一个代码单元,通常是一个函数或方法。

通常,设计单个单元测试是为了测试通过一个函数或特定分支的特定执行流程,这使得将失败的单元测试和导致失败的 bug 对应起来变得容易。

理想情况下,单元测试很少使用或不使用外部资源,从而隔离它们并使它们更快。

单元测试套件通过在开发过程的早期发现问题来帮助维护高质量的产品。有效的单元测试可以在代码离开开发人员机器之前捕获 bug,或者至少可以在特定分支上的持续集成环境中捕获 bug。这标志着好的和坏的单元测试之间的区别:好的测试通过尽早捕获 bug 并使测试更快来提高开发人员的生产力。坏的测试降低了开发人员的工作效率。

当测试附带的特性时,生产率通常会降低。当代码更改时测试会失败,即使它仍然是正确的。发生这种情况是因为输出的不同,但在某种程度上是因为它不是 函数契约 function’s contract 的一部分。

因此,一个好的单元测试可以帮助执行函数所提交的契约。

如果单元测试中断,那意味着该契约被违反了,应该(通过更改文档和测试)明确修改,或者(通过修复代码并保持测试不变)来修复。

虽然将测试限制为只执行公共契约是一项需要学习的复杂技能,但有一些工具可以提供帮助。

其中一个工具是 Hamcrest,这是一个用于编写断言的框架。最初是为基于 Java 的单元测试而发明的,但它现在支持多种语言,包括 Python

Hamcrest 旨在使测试断言更容易编写和更精确。

def add(a, b):
    return a + b

from hamcrest import assert_that, equal_to

def test_add():
    assert_that(add(2, 2), equal_to(4))  

这是一个用于简单函数的断言。如果我们想要断言更复杂的函数怎么办?

def test_set_removal():
    my_set = {1, 2, 3, 4}
    my_set.remove(3)
    assert_that(my_set, contains_inanyorder([1, 2, 4]))
    assert_that(my_set, is_not(has_item(3)))

注意,我们可以简单地断言其结果是任何顺序的 124,因为集合不保证顺序。

我们也可以很容易用 is_not 来否定断言。这有助于我们编写精确的断言,使我们能够把自己限制在执行函数的公共契约方面。

然而,有时候,内置的功能都不是我们真正需要的。在这些情况下,Hamcrest 允许我们编写自己的 匹配器 matchers 。

想象一下以下功能:

def scale_one(a, b):
    scale = random.randint(0, 5)
    pick = random.choice([a,b])
    return scale * pick

我们可以自信地断言其结果均匀地分配到至少一个输入。

匹配器继承自 hamcrest.core.base_matcher.BaseMatcher,重写两个方法:

class DivisibleBy(hamcrest.core.base_matcher.BaseMatcher):
    def __init__(self, factor):
        self.factor = factor

    def _matches(self, item):
        return (item % self.factor) == 0

    def describe_to(self, description):
        description.append_text('number divisible by')
        description.append_text(repr(self.factor))

编写高质量的 describe_to 方法很重要,因为这是测试失败时显示的消息的一部分。

def divisible_by(num):
    return DivisibleBy(num)

按照惯例,我们将匹配器包装在一个函数中。有时这给了我们进一步处理输入的机会,但在这种情况下,我们不需要进一步处理。

def test_scale():
    result = scale_one(3, 7)
    assert_that(result,
                any_of(divisible_by(3),
                divisible_by(7)))

请注意,我们将 divisible_by 匹配器与内置的 any_of 匹配器结合起来,以确保我们只测试函数提交的内容。

在编辑这篇文章时,我听到一个传言,取 “Hamcrest” 这个名字是因为它是 “matches” 字母组成的字谜。嗯…

>>> assert_that("matches", contains_inanyorder(*"hamcrest")
Traceback (most recent call last):
  File "", line 1, in 
  File "/home/moshez/src/devops-python/build/devops/lib/python3.6/site-packages/hamcrest/core/assert_that.py", line 43, in assert_that
    _assert_match(actual=arg1, matcher=arg2, reason=arg3)
  File "/home/moshez/src/devops-python/build/devops/lib/python3.6/site-packages/hamcrest/core/assert_that.py", line 57, in _assert_match
    raise AssertionError(description)
AssertionError:
Expected: a sequence over ['h', 'a', 'm', 'c', 'r', 'e', 's', 't'] in any order
      but: no item matches: 'r' in ['m', 'a', 't', 'c', 'h', 'e', 's']

经过进一步的研究,我找到了传言的来源:它是 “matchers” 字母组成的字谜。

>>> assert_that("matchers", contains_inanyorder(*"hamcrest"))
>>>

如果你还没有为你的 Python 代码编写单元测试,那么现在是开始的好时机。如果你正在为你的 Python 代码编写单元测试,那么使用 Hamcrest 将允许你使你的断言更加精确,既不会比你想要测试的多也不会少。这将在修改代码时减少误报,并减少修改工作代码的测试所花费的时间。


via: https://opensource.com/article/18/8/robust-unit-tests-hamcrest

作者:Moshe Zadka 选题:lujun9972 译者:MjSeven 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

相关内容

富士通测试用AI辅助超市店...
7月15日,富士通公司将在日本关东近郊运营超市的永旺食品模式公司开...
2026-07-16 22:34:23
搜狐AI健康 | 真人医生...
图说 / 蚂蚁旗下健康AI产品蚂蚁阿福近期正式推出“医生把关”功能...
2026-06-24 09:57:21
微信原生 AI 助手灰度测...
6 月 20 日,微信原生 AI 助手「小微」扩大灰度测试范围。它...
2026-06-22 17:49:44
微信原生AI助手“小微”灰...
目前该功能仍在小范围内测中,若未获得内测名额,建议您后续留意版本更...
2026-06-20 18:27:04
AI四巨头内部报告首度公开...
新智元报道 【新智元导读】当四大巨头首次允许第三方深入测试最强模...
2026-05-24 14:05:53
小米开源OmniVoice...
PChome 5月7日消息,小米技术官微官宣,小米AI实验室新一代...
2026-05-08 13:17:52

热门资讯

“Linux 中国” 开源社区... 这是一个艰难的决定 —— 这不是调侃,而是当你真正做出改变了你十几年生活轨迹的决定时,你就会明白这个...
硬核观察 #1263 德国铁路... #1 德国铁路公司招聘 Windows for Workgroups 3.11 管理员该职位要求了解...
人工智能教程(七):Sciki... 在本系列的 上一篇文章 中,我们用 TensorFlow 构建了第一个神经网络,然后还通过 Kera...
关闭 WSL 中正在运行的 L... 以下是使用 WSL 关闭在 Windows 内运行的 Linux 系统的不同方法。你使用 WSL 在...
MX Linux 23.2 “... 最新的 MX Linux 23.2 小版本更新带来了基本的改进和新增功能。MX Linux 推出了 ...
硬核观察 #1262 网络上最... #1 网络上最古老的软件存档库之一即将关闭美国新墨西哥州立大学(NMSU)最近宣布,即将于 2024...
如何在 RHEL 上通过绑定配... 在 Linux 中,你可以根据自己的需要创建高级网络设置,如 网络绑定 Network Bondin...
Linux Matrix 消息... Matrix 用户可以升级 Fractal 6 了!Fractal 是目前 最好的 Matrix 客...
如何通过 VLC 使用字幕 使用 VLC 媒体播放器播放和管理字幕的新手指南。我是一个超级动漫迷,如果你想观看最新的剧集,那么你...
硬核观察 #1261 X 计划... #1 X 计划在奥斯汀建立内容审核总部据报道,该部门将招聘 100 名全职员工,将主要关注 CSE ...