python - pytest 参数化 session 装置执行次数过多

标签 python pytest

考虑以下测试代码,它将模拟运行结果与预期结果进行比较。运行结果的值取决于参数化 fixture paramfixture的值,它提供了两个值,因此运行结果有两种可能的变体。由于它们都是 session 装置,我们应该期望 run_result 装置只执行两次。

现在,请看一下测试用例 test_run_result,它接收 run_result 和 expected_result fixture 进行比较,还接收 tolerance fixture,它用两个值进行参数化。测试用例检查预期和结果之间的差异是否在容差范围内。请注意,运行不依赖于公差。

出于某种原因,我不明白 Pytest 执行了 run_result() fixture 三次。你能解释为什么吗?

这是使用 pytest vers 测试的。 2.9.1

顺便说一下,如果测试用例没有参数化或者使用装饰器而不是固定装置进行参数化,run_result 固定装置将只执行两次,即:@pytest.mark.parametrize('tolerance', [1e-8 , 1e-11]).

import pytest

runcounter = 0

@pytest.fixture(scope="session", params=[1e-8, 1e-11])
def tolerance(request):
    """Precision in floating point compare."""
    return request.param

@pytest.fixture(scope='session', params=[1, 2])
def paramfixture(request):
    return request.param

@pytest.fixture(scope="session")
def expected_result(paramfixture):
    return 1 + paramfixture

@pytest.fixture(scope='session')
def run_result(paramfixture):
    global runcounter
    runcounter = runcounter + 1
    print "Run #", runcounter, 'param:', paramfixture
    return 1 + paramfixture

def test_run_result(run_result, expected_result, tolerance):
    print "run_result: %d, expected_result: %d" % (run_result, expected_result)
    assert abs(run_result - expected_result) < tolerance

Pytest 截图:

$ py.test -vs test/end2end/test_temp.py
===================================================== test session starts ======================================================
platform linux2 -- Python 2.7.11, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 -- /home/f557010/.conda/envs/sfpdev/bin/python
cachedir: .cache
rootdir: /home/f557010/svndev/SFP, inifile: pytest.ini
collected 4 items

test/end2end/test_temp.py::test_run_result[1e-08-1] Run # 1 param: 1
run_result: 2, expected_result: 2
PASSED
test/end2end/test_temp.py::test_run_result[1e-08-2] Run # 2 param: 2
run_result: 3, expected_result: 3
PASSED
test/end2end/test_temp.py::test_run_result[1e-11-2] 
run_result: 3, expected_result: 3
PASSED
test/end2end/test_temp.py::test_run_result[1e-11-1] Run # 3 param: 1
run_result: 2, expected_result: 2
PASSED

=================================================== 4 passed in 0.01 seconds ===================================================

最佳答案

pytest 的参数化就是获取固定装置并在合理的生命周期内保持它。它不会缓存所有的输入->输出映射。这不是您在这里想要的,但如果您将固定装置视为数据库连接或 tcp 连接(如示例中的 smtp)之类的东西,它就有意义了。

你仍然有一个很好的论据可以证明对 pytest 的足够的自省(introspection)和优化会让你受益(这里假设 run_result 非常昂贵并且你希望最小化运行)。

为什么它在这里做“错误的事情”?如果仔细观察灯具,公差是“一阶”或最接近的参数化灯具。

“有效”的丑陋、难以理解的更改:

@pytest.fixture(scope="session", params=[0.01, 0.0002])
def tol(request):
    """Precision in floating point compare."""
    return request.param

@pytest.fixture(scope="session")
def tolerance(tol):
    """Precision in floating point compare."""
    return tol

为什么这行得通?它将公差参数删除到与其他灯具上的参数相同的“级别”。有了这个,pytest 实际上只运行 run_tests 两次。

============================================ test session starts ============================================
<snip>
collected 4 items

test_tolerance.py::test_run_result[1-0.01] Run # 1 param: 1
run_result: 2, expected_result: 2 tolerance: 0.010000
PASSED
test_tolerance.py::test_run_result[1-0.0002]
run_result: 2, expected_result: 2 tolerance: 0.000200
PASSED
test_tolerance.py::test_run_result[2-0.0002] Run # 2 param: 2
run_result: 3, expected_result: 3 tolerance: 0.000200
PASSED
test_tolerance.py::test_run_result[2-0.01]
run_result: 3, expected_result: 3 tolerance: 0.010000
PASSED

========================================= 4 passed in 0.01 seconds ==========================================

您应该使用该代码吗?请尽量不要,因为它太难理解了,如果你使用这样的 hack,请大量评论以“自责”。

你问了“为什么”,这里的关键是 tolerance 和 paramfixture 的参数处于不同的嵌套级别,“最接近”的那个是迭代最慢的那个。 fixtures 不缓存在这里,它们只是按逻辑顺序使用,最里面的迭代速度最快。

关于python - pytest 参数化 session 装置执行次数过多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39729558/

相关文章:

python - 如何找到图像给定部分的平均值

python - pytest parametrize - 来自 CSV 的行作为测试用例

python - 在pytest中重命名参数化测试

python - 现在为什么不在测试中使用 python 的 assert 语句呢?

python - 长时间运行的 py.test 在第一次失败时停止

python - 用于 Visual Studio 的 Python 工具上的 Pytest

python - 如何在python中创建cmyk图像

python - 如何在 Python 中为返回 None 但在磁盘中写入文件的函数编写文档字符串?

python - 从日期时间对象中提取日期和月份

python - 如何在 Python 中连接位