赞
踩
之前一文中提到了,到底pytest_repeat
插件的具体功能是如何实现的呢?相信具体了解了该插件,其他三方插件也可以很快了解它内部运行机制。
pytest_repeat
插件如何实现重复执行用例最笨的办法,当然是运行多次,但这显然不是我们需要的。在装饰器复习这片文章中,我们复习了装饰器相关知识点,知道装饰器可以在不修改原始代码的情况下,动态的增加功能或修改函数行为。显然,这里我们就可以使用装饰器来实现重复功能。
- def repeat(nums: int = 2):
-
- def wrapper(func):
-
- @functools.wraps(func)
- def decorator(*args, **kwargs):
- for i in range(nums):
- func(*args, **kwargs)
-
- return decorator
-
- return wrapper
这段代码很好理解,定义了带有自定义参数的装饰器,表示装饰器内部函数执行的次数。这样在用例上使用@repeat()
装饰器就可以达到用例重复运行的目的。但是统计结果仍然为1条用例。使用过pytest_repeat
的同学知道它的统计结果是多条用例?那是如何做的呢,通过源码一探究竟。
pytest_repeat
如何实现重复执行源码解读
- def pytest_addoption(parser):
- parser.addoption(
- '--count',
- action='/pytest-dev/pytest-repeat/blob/v0.9.1/store',
- default=1,
- type=int,
- help='Number of times to repeat each test')
-
- parser.addoption(
- '--repeat-scope',
- action='/pytest-dev/pytest-repeat/blob/v0.9.1/store',
- default='function',
- type=str,
- choices=('function', 'class', 'module', 'session'),
- help='Scope for repeating tests')
这段代码定义了两个命令行选项:
--count
:用于指定每个测试用例要重复执行的次数。action=store
表示将值存储在命令行参数中。--repeat-scope
:用于指定重复测试用例的作用域,可以选择 function
、class
、module
或 session
。默认值是 function
。action=store
表示将值存储在命令行参数中。这两个选项都是通过 parser.addoption
方法添加到 pytest 的命令行解析器中的。
当运行 pytest 并指定 --count
、--repeat-scope
参数时,pytest-repeat
插件将获取这些参数并自动为测试用例生成多个重复执行的实例。
例如,如果运行以下命令:
pytest --count=2 --repeat-scope=function
pytest-repeat
将会在执行 test_my_function
测试用例时,自动执行该测试用例两次。
action=store
是 argparse
模块中的一个参数,它指定了在命令行解析过程中如何处理选项的值。具体地说,action=store
表示将选项的值存储在命令行参数中。
当使用 parser.addoption
方法添加选项到命令行解析器时,通过指定 action=store
,选项的值将被存储在解析结果中,可以通过相应的属性来获取这些值。
例如,当运行 pytest 命令时,指定的 --count
和 --repeat-scope
选项的值会存储在命令行参数中。你可以使用 request.config.getoption
方法来获取这些存储的值,例如:
- def test_example(request):
- count = request.config.getoption('--count')
- # count = request.config.option.count 这样也能获取
- repeat_scope = request.config.getoption('--repeat-scope')
- # repeat_scope = request.config.option.repeat_scope
- # 使用获取到的值进行后续操作
在上面的示例代码中,使用 request.config.getoption
方法从命令行参数中获取了 --count
和 --repeat-scope
的值,并分别存储在 count
和 repeat_scope
变量中。
总结:action=store
是 argparse
模块中的一个参数,用于指定将选项的值存储在命令行参数中。在 pytest 中,通过使用 request.config.getoption
方法可以获取存储在命令行参数中的选项值。
- def pytest_configure(config):
- config.addinivalue_line(
- 'markers',
- 'repeat(n): run the given test function `n` times.')
这个函数在 pytest 的配置阶段被调用,通过调用 config.addinivalue_line()
将自定义标记 'repeat(n)'
添加到 pytest 的标记列表中。'repeat(n)'
标记可以用于指定一个测试函数需要重复运行的次数。
- @pytest.fixture
- def __pytest_repeat_step_number(request):
- marker = request.node.get_closest_marker("repeat")
- count = marker and marker.args[0] or request.config.option.count
- if count > 1:
- try:
- return request.param
- except AttributeError:
- if issubclass(request.cls, TestCase):
- warnings.warn(
- "Repeating unittest class tests not supported")
- else:
- raise UnexpectedError(
- "This call couldn't work with pytest-repeat. "
- "Please consider raising an issue with your usage.")
这个 fixture 函数用于获取当前的重复运行步骤编号。它首先检查测试函数是否被 'repeat'
标记装饰,并从标记中获取重复次数。如果没有标记,则使用命令行参数中的 --count
参数作为默认值。
- @pytest.hookimpl(trylast=True)
- def pytest_generate_tests(metafunc):
- count = metafunc.config.option.count
- m = metafunc.definition.get_closest_marker('repeat')
- if m is not None:
- count = int(m.args[0])
- if count > 1:
- metafunc.fixturenames.append("__pytest_repeat_step_number")
-
- def make_progress_id(i, n=count):
- return '{0}-{1}'.format(i + 1, n)
-
- scope = metafunc.config.option.repeat_scope
- metafunc.parametrize(
- '__pytest_repeat_step_number',
- range(count),
- indirect=True,
- ids=make_progress_id,
- scope=scope
- )
这个 pytest_generate_tests
钩子函数会在 pytest 收集到所有测试函数之后被调用,并且它被设置为 trylast=True
,以确保在其他钩子函数执行完毕之后再执行。
metafunc.config.option.count
的值,该值表示测试用例重复执行的次数。metafunc.definition.get_closest_marker('repeat')
来获取测试用例是否有被标记为 repeat
的 marker。repeat
的 marker 标记,则从 marker 中获取重复执行的次数,并将其赋值给 count
变量。metafunc.fixturenames.append("__pytest_repeat_step_number")
添加了一个名为 __pytest_repeat_step_number
的 fixture 名称到 metafunc
的 fixture 列表中。make_progress_id
,用于生成测试用例的进度标识符。metafunc.config.option.repeat_scope
的值,确定了重复执行的作用域。metafunc.parametrize
来动态生成测试用例。它使用了 range(count)
来生成重复执行的步骤数量作为参数,并将 indirect=True
设置为在加载 fixture 时进行间接调用。同时,使用了之前定义的进度标识符生成函数和作用域来设置参数化的其他选项。可以看到最终是通过参数化来实现的,这也就是为啥重复执行多次能当做多条用例。
相信你看我之后依然有很多疑问,fixture
是啥?mark
是啥?参数request
是啥?钩子函数是啥?parametrize
参数化是啥?这些疑问可以先留着,这片内容我们主要讲了pytest_repeat
具体实现逻辑,然后引出了这么多知识点,别着急,之后会一个个逐一消灭。
最后:下方这份完整的软件测试视频教程已经整理上传完成,需要的朋友们可以自行领取【保100%免费】
我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。