【问题标题】:pytest dynamically parametrized testpytest 动态参数化测试
【发布时间】:2018-06-12 13:01:04
【问题描述】:

我创建了一个“动态”参数列表,我将其传递给参数化。

OPTIONS = ['a', 'b', 'c']

def get_unique_pairs():
    unique_list = []
    for first in OPTIONS:
        for second OPTIONS:
            if first == second:
                continue
            unique_list.append({'first':first, 'second':second))
    return unique_list

def some_func()
    unique_pairs = get_unique_pairs()
    result = []
    for pair in unique_pair:
        if test(pair):
           continue
        else:
           result.append(pair)
    return pair

@pytest.mark.parametrize('param', some_fnc())
def test_fnc(param):
    first = param['first']
    second = param['second']

我希望传递给test_fnc 的输入是[('a','b'),('a','c')...('c','b')],其中第一个和第二个元素永远不会相同。我正在使用一些额外的逻辑来进一步删除特定的对。

当我运行测试时,我得到了输出:

::test_fnc[param0] PASSED
::test_fnc[param1] PASSED
::test_fnc[param2] PASSED

我有两个问题:

  1. 我不完全确定如何描述我正在做什么以查找更多文档/帮助。
  2. 我想要更多描述性的输出(即不是param0),并且我想继续使用字典将数据传递给测试。

【问题讨论】:

  • 我的印象是您的get_unique_pairs 可以替换为list(itertools.combinations(OPTIONS, 2))。另外,看看生成器函数和生成器表达式,它们可以使您的代码更简洁和惯用。
  • 这很酷 - 谢谢。我会玩,我希望它生成 ['c', 'a'] - 反转组合。
  • 组合迭代器有:product、permutations、combinations 和combinations_with_replacement。 combinations(p, r) 迭代器以排序顺序返回 r 长度的元组,没有重复的元素。 Product 相当于你的嵌套 for 循环:[(a, b) for a, b in product(OPTIONS, OPTIONS) if a != b]
  • itertools.permutations(OPTIONS, 2) 是一种更简洁的方式来写我正在做的事情!
  • 每天你都会学到新东西。欢迎来到 StackOverflow!这里的 Python 社区很棒。

标签: python pytest


【解决方案1】:

我会这样写:

import pytest
import itertools


OPTIONS = ['a', 'b', 'c']

@pytest.mark.parametrize(
    'param',
    itertools.permutations(OPTIONS, 2),
    ids=lambda pair: "first={}, second={}".format(*pair)
)
def test_fn(param):
    first, second = param
    assert first != second

结果:

> pytest --verbose 
================================ test session starts =================================
platform linux2 -- Python 2.7.12, pytest-3.6.1, py-1.5.3, pluggy-0.6.0 -- /usr/bin/python
cachedir: .pytest_cache
rootdir: /home/paulos/work/lixo/tests, inifile:
collected 6 items

test_foo.py::test_fn[first=a, second=b] PASSED                                     [ 16%]
test_foo.py::test_fn[first=a, second=c] PASSED                                     [ 33%]
test_foo.py::test_fn[first=b, second=a] PASSED                                     [ 50%]
test_foo.py::test_fn[first=b, second=c] PASSED                                     [ 66%]
test_foo.py::test_fn[first=c, second=a] PASSED                                     [ 83%]
test_foo.py::test_fn[first=c, second=b] PASSED                                     [100%]

================================ 6 passed in 0.03 seconds ================================

[更新]

我认为这个答案是我将使用的解决方案。每一天都是上学日! (出于好奇,有没有一种方法可以将“参数”变成“第一,第二”之类的东西,所以让 test_foo(param)成为 test_foo(第一,第二)。我不确定这是否真的有帮助......但我很好奇——F. Elliot

如果您不介意test_fn[a-b] 而不是test_fn[a, b]

@pytest.mark.parametrize(
    'first,second',
    itertools.permutations(OPTIONS, 2),
)
def test_fn(first, second):
    assert first != second

实际上,我们并没有真正使用--verbose 运行测试,所以大多数时候每个测试的输出只是一个点。

【讨论】:

  • 我认为这个答案是我将使用的解决方案。每一天都是上学日! (出于好奇,有没有一种方法可以将“参数”变成“第一,第二”之类的东西,所以让 test_foo(param)成为 test_foo(第一,第二)。我不确定这是否真的有帮助......但我很好奇
【解决方案2】:
  1. 正如评论中提到的Paulo Scardine,不要重新发明轮子,使用itertools.combinations
  2. 您正在寻找ids argument in parametrize hook。它可以是每个参数的名称列表,也可以是接受参数并返回字符串的函数 - repr 是内置类型的简单解决方案。

组合示例:

import itertools
import pytest


opts = ['a', 'b', 'c']


@pytest.mark.parametrize('param', itertools.combinations(opts, 2), ids=repr)
def test_fn(param):
    first = param[0]
    second = param[1]
    assert first != second

【讨论】:

  • 我发现这个和 Paulos 的帖子很有用 - 也谢谢你的链接,我没有意识到 ids 可能是一个函数。 (我花了一些时间尝试看看我是否可以通过使用字典来分离参数,但我想我现在就放弃对字典的痴迷!)
  • 您可以根据需要拥有 dicts - 只需从 itertools.combinations(opts, 2) 构建它们,例如[{'first': first, 'second': second} for first, second in itertools.combinations(opts, 2)].
  • 如何更改“ID”?我觉得字典的键正在传入
  • 您可以继续使用repr,或者编写一个自定义格式函数,例如def dump(param): return ', '.join('{}={}'.format(k, v) for k, v in param.items())并与ids=dump一起使用。这会给你像test_fn[first=a, second=b]这样的测试名称。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-15
  • 1970-01-01
相关资源
最近更新 更多