news 2026/1/16 11:30:41

深入理解 pytest-repeat 插件的工作原理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
深入理解 pytest-repeat 插件的工作原理

在文章《无需修改代码,深入探究 pytest 如何自动查找并加载三方插件》中最后提到了,到底pytest_repeat插件的具体功能是如何实现的呢?

相信具体了解了该插件,其他三方插件也可以很快了解它内部运行机制。

不使用pytest_repeat插件如何实现重复执行用例

不使用pytest_repeat插件如何实现重复执行用例

最笨的办法,当然是运行多次,但这显然不是我们需要的。

在装饰器复习这篇文章中,我们复习了装饰器相关知识点,知道装饰器可以在不修改原始代码的情况下,动态的增加功能或修改函数行为。

显然,这里我们就可以使用装饰器来实现重复功能。

  1. def repeat(nums: int = 2):

  2. def wrapper(func):

  3. @functools.wraps(func)

  4. def decorator(*args, **kwargs):

  5. for i in range(nums):

  6. func(*args, **kwargs)

  7. return decorator

  8. return wrapper

这段代码很好理解,定义了带有自定义参数的装饰器,表示装饰器内部函数执行的次数。

这样在用例上使用@repeat()装饰器就可以达到用例重复运行的目的。

但是统计结果仍然为1条用例。使用过pytest_repeat的同学知道它的统计结果是多条用例?那是如何做的呢,通过源码一探究竟。

pytest_repeat如何实现重复执行

源码直达:https://github.com/pytest-dev/pytest-repeat/blob/v0.9.1/pytest_repeat.py

源码解读

  1. def pytest_addoption(parser):

  2. parser.addoption(

  3. '--count',

  4. action='/pytest-dev/pytest-repeat/blob/v0.9.1/store',

  5. default=1,

  6. type=int,

  7. help='Number of times to repeat each test')

  8. parser.addoption(

  9. '--repeat-scope',

  10. action='/pytest-dev/pytest-repeat/blob/v0.9.1/store',

  11. default='function',

  12. type=str,

  13. choices=('function', 'class', 'module', 'session'),

  14. help='Scope for repeating tests')

这段代码定义了两个命令行选项:

  • --count:用于指定每个测试用例要重复执行的次数。action=store表示将值存储在命令行参数中。

  • --repeat-scope:用于指定重复测试用例的作用域,可以选择functionclassmodulesession

    默认值是functionaction=store表示将值存储在命令行参数中。

这两个选项都是通过parser.addoption方法添加到pytest的命令行解析器中的。

当运行pytest并指定--count--repeat-scope参数时,pytest-repeat插件将获取这些参数并自动为测试用例生成多个重复执行的实例。

例如,如果运行以下命令:

pytest --count=2 --repeat-scope=function

pytest-repeat将会在执行test_my_function测试用例时,自动执行该测试用例两次。

action=storeargparse模块中的一个参数,它指定了在命令行解析过程中如何处理选项的值。

具体地说,action=store表示将选项的值存储在命令行参数中。

当使用parser.addoption方法添加选项到命令行解析器时,通过指定action=store,选项的值将被存储在解析结果中,可以通过相应的属性来获取这些值。

例如,当运行pytest命令时,指定的--count--repeat-scope选项的值会存储在命令行参数中。

你可以使用request.config.getoption方法来获取这些存储的值,例如:

  1. def test_example(request):

  2. count = request.config.getoption('--count')

  3. # count = request.config.option.count 这样也能获取

  4. repeat_scope = request.config.getoption('--repeat-scope')

  5. # repeat_scope = request.config.option.repeat_scope

  6. # 使用获取到的值进行后续操作

在上面的示例代码中,使用request.config.getoption方法从命令行参数中获取了--count--repeat-scope的值,并分别存储在countrepeat_scope变量中。

总结:action=storeargparse模块中的一个参数,用于指定将选项的值存储在命令行参数中。

pytest中,通过使用request.config.getoption方法可以获取存储在命令行参数中的选项值。​​​​​​​

  1. def pytest_configure(config):

  2. config.addinivalue_line(

  3. 'markers',

  4. 'repeat(n): run the given test function `n` times.')

这个函数在pytest的配置阶段被调用,通过调用config.addinivalue_line()将自定义标记'repeat(n)'添加到pytest的标记列表中。

'repeat(n)'标记可以用于指定一个测试函数需要重复运行的次数。​​​​​​​

  1. @pytest.fixture

  2. def __pytest_repeat_step_number(request):

  3. marker = request.node.get_closest_marker("repeat")

  4. count = marker and marker.args[0] or request.config.option.count

  5. if count > 1:

  6. try:

  7. return request.param

  8. except AttributeError:

  9. if issubclass(request.cls, TestCase):

  10. warnings.warn(

  11. "Repeating unittest class tests not supported")

  12. else:

  13. raise UnexpectedError(

  14. "This call couldn't work with pytest-repeat. "

  15. "Please consider raising an issue with your usage.")

这个fixture函数用于获取当前的重复运行步骤编号。它首先检查测试函数是否被'repeat'标记装饰,并从标记中获取重复次数。

如果没有标记,则使用命令行参数中的--count参数作为默认值。​​​​​​​

  1. @pytest.hookimpl(trylast=True)

  2. def pytest_generate_tests(metafunc):

  3. count = metafunc.config.option.count

  4. m = metafunc.definition.get_closest_marker('repeat')

  5. if m is not None:

  6. count = int(m.args[0])

  7. if count > 1:

  8. metafunc.fixturenames.append("__pytest_repeat_step_number")

  9. def make_progress_id(i, n=count):

  10. return '{0}-{1}'.format(i + 1, n)

  11. scope = metafunc.config.option.repeat_scope

  12. metafunc.parametrize(

  13. '__pytest_repeat_step_number',

  14. range(count),

  15. indirect=True,

  16. ids=make_progress_id,

  17. scope=scope

  18. )

这个pytest_generate_tests钩子函数会在pytest收集到所有测试函数之后被调用,并且它被设置为trylast=True,以确保在其他钩子函数执行完毕之后再执行。

  1. 首先,代码获取了metafunc.config.option.count的值,该值表示测试用例重复执行的次数。

  2. 然后,代码调用metafunc.definition.get_closest_marker('repeat')来获取测试用例是否有被标记为repeatmarker

  3. 如果有repeatmarker标记,则从marker中获取重复执行的次数,并将其赋值给count变量。

  4. 接下来,代码通过metafunc.fixturenames.append("__pytest_repeat_step_number")添加了一个名为__pytest_repeat_step_numberfixture名称到metafuncfixture列表中。

  5. 之后,定义了一个辅助函数make_progress_id,用于生成测试用例的进度标识符。

  6. 根据metafunc.config.option.repeat_scope的值,确定了重复执行的作用域。

  7. 最后,通过调用metafunc.parametrize来动态生成测试用例。它使用了range(count)来生成重复执行的步骤数量作为参数,并将indirect=True设置为在加载fixture时进行间接调用。

    同时,使用了之前定义的进度标识符生成函数和作用域来设置参数化的其他选项。

可以看到最终是通过参数化来实现的,这也就是为啥重复执行多次能当做多条用例。

最后

相信你看我之后依然有很多疑问,fixture是啥?mark是啥?参数request是啥?钩子函数是啥?parametrize参数化是啥?

这些疑问可以先留着,这片内容我们主要讲了pytest_repeat具体实现逻辑,然后引出了这么多知识点,别着急,之后会一个个逐一消灭。

感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!有需要的小伙伴可以点击下方小卡片领取

​​​​​​​

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/1/8 1:38:00

Open-AutoGLM自动化控制全解析,掌握未来人机交互的底层密码

第一章:Open-AutoGLM控制电脑Open-AutoGLM 是一款基于自然语言理解与自动化执行的智能代理系统,能够通过语义解析将用户指令转化为具体的计算机操作。其核心能力在于连接大语言模型与操作系统接口,实现跨平台的自动化控制,如文件管…

作者头像 李华
网站建设 2026/1/13 17:23:03

Open-AutoGLM部署踩坑实录:3大常见问题与终极解决方案

第一章:Open-AutoGLM部署踩坑实录:3大常见问题与终极解决方案在本地部署 Open-AutoGLM 过程中,开发者常因环境配置、依赖冲突和模型加载机制不熟悉而遭遇阻塞。以下归纳了三大高频问题及其可落地的解决策略。依赖版本冲突导致启动失败 Open-A…

作者头像 李华
网站建设 2026/1/12 2:17:56

Open-AutoGLM 阿里云落地实践(99%工程师忽略的4个核心配置细节)

第一章:Open-AutoGLM 阿里云落地实践概述Open-AutoGLM 是阿里云推出的一款面向生成式 AI 应用的自动化大模型工具链,旨在降低企业在私有化或混合云环境中部署、调优和管理大语言模型的技术门槛。该方案深度融合了阿里云弹性计算、容器服务(AC…

作者头像 李华
网站建设 2026/1/12 8:57:45

Open-AutoGLM测试常见失败原因解析:90%工程师忽略的2个致命细节

第一章:Open-AutoGLM测试常见失败原因解析:90%工程师忽略的2个致命细节在使用 Open-AutoGLM 进行自动化模型测试时,许多工程师频繁遭遇测试失败,却往往将问题归结于模型精度或数据质量。实际上,超过90%的失败案例源于两…

作者头像 李华
网站建设 2026/1/10 10:01:11

生产环境日志脱敏方案:保护用户隐私数据

被安全部门约谈了一次。 原因是日志里明文打印了用户手机号、身份证号,还被导出到了测试环境。这要是出了事,GDPR罚款能让公司破产。 花了两周时间做日志脱敏,整理一下方案。 为什么要日志脱敏 日志里经常会有: 手机号、身份…

作者头像 李华
网站建设 2026/1/13 15:57:43

零基础用户如何访问机顶盒固件下载官网(家用电视服务)

老电视卡顿、机顶盒死机?别急着换,一招“刷固件”让你家的盒子满血复活! 你有没有遇到过这种情况: 晚上一家人正看得起劲,电视突然卡在广告页不动了; 开机半天进不去系统,遥控器按啥都没反应…

作者头像 李华