【问题标题】:write pytest test function return value to file with pytest.hookimpl使用 pytest.hookimpl 将 pytest 测试函数返回值写入文件
【发布时间】:2019-12-04 14:49:15
【问题描述】:

我正在寻找一种访问测试函数返回值的方法,以便将该值包含在测试报告文件中(类似于http://doc.pytest.org/en/latest/example/simple.html#post-process-test-reports-failures)。

我想使用的代码示例:

# modified example code from http://doc.pytest.org/en/latest/example/simple.html#post-process-test-reports-failures

import pytest
import os.path

@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
    # execute all other hooks to obtain the report object
    outcome = yield
    rep = outcome.get_result()

    if rep.when == "call" and rep.passed:
        mode = "a" if os.path.exists("return_values") else "w"
        with open("return_values.txt", mode) as f:
            # THE FOLLOWING LINE IS THE ONE I CANNOT FIGURE OUT
            # HOW DO I ACCESS THE TEST FUNCTION RETURN VALUE?
            return_value = item.return_value
            f.write(rep.nodeid + ' returned ' + str(return_value) + "\n")

我希望将返回值写入文件“return_values.txt”。相反,我得到了一个 AttributeError。

背景(如果您可以推荐一种完全不同的方法):

我有一个 Python 库,用于对给定问题进行数据分析。我有一组标准的测试数据,我会定期运行我的分析,以生成关于分析算法质量的各种“基准”指标。例如,一个这样的指标是分析代码产生的归一化混淆矩阵的轨迹(我希望它尽可能接近 1)。另一个指标是产生分析结果的 CPU 时间。

我正在寻找一种将这些基准测试结果包含到 CI 框架(当前为 Jenkins)中的好方法,以便轻松查看提交是提高还是降低了分析性能。由于我已经在 CI 序列中运行 pytest,并且因为我想将 pytest 的各种功能用于我的基准测试(夹具、标记、跳过、清理),所以我考虑在 pytest 中简单地添加一个后处理钩子(参见 @987654322 @) 收集测试函数运行时间和返回值并将它们(或仅标记为基准的那些)报告到一个文件中,该文件将被我的 CI 框架收集并存档为测试工件。

我对解决这个问题的其他方法持开放态度,但我的谷歌搜索结论是 pytest 是最接近已经提供我需要的框架。

【问题讨论】:

  • 测试函数没有返回值,pytest 忽略它们。不过,您可以将自定义数据存储在测试函数本身中,例如在request.config: 类似request.config._test_results[request.node.nodeid] = mydata,然后在hookimpl 中通过item.config._test_results[item.nodeid] 访问它。
  • 谢谢!我会接受这个作为答案。

标签: python return pytest return-value benchmarking


【解决方案1】:

pytest 忽略测试函数返回值,可见in the code

@hookimpl(trylast=True)
def pytest_pyfunc_call(pyfuncitem):
    testfunction = pyfuncitem.obj
    ...
    testfunction(**testargs)
    return True

但是,您可以在测试函数中存储您需要的任何内容;我通常为此使用config 对象。示例:将以下 sn-p 放入您的conftest.py

import pathlib
import pytest


def pytest_configure(config):
    # create the dict to store custom data
    config._test_results = dict()


@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
    # execute all other hooks to obtain the report object
    outcome = yield
    rep = outcome.get_result()

    if rep.when == "call" and rep.passed:
        # get the custom data
        return_value = item.config._test_results.get(item.nodeid, None)
        # write to file
        report = pathlib.Path('return_values.txt')
        with report.open('a') as f:
            f.write(rep.nodeid + ' returned ' + str(return_value) + "\n")

现在将数据存储在测试中:

def test_fizz(request):
    request.config._test_results[request.node.nodeid] = 'mydata'

【讨论】:

  • 谢谢!这对我来说并不明显,所以仅供参考 - 你需要将第二块代码放在 conftest.py 文件中。
【解决方案2】:

分享同样的问题,这是我想出的不同解决方案:

在测试中使用夹具record_property

def test_mytest(record_property):
    record_property("key", 42)

然后在conftest.py 中我们可以使用pytest_runtest_teardown hook:

#conftest.py
def pytest_runtest_teardown(item, nextitem):
    results = dict(item.user_properties)
    if not results:
        return
    with open(f'{item.name}_return_values.txt','a') as f:
        for key, value in results.items():
            f.write(f'{key} = {value}\n')

然后是test_mytest_return_values.txt的内容:

key = 42

两个重要说明:

  1. 即使测试失败,也会执行此代码。我找不到获得测试结果的方法。
  2. 这可以与heofling 的答案结合使用results = dict(item.user_properties) 来获取在测试中添加的键和值,而不是在配置中添加字典然后在测试中访问它。

【讨论】:

  • 我无法使用 @hoefling 的 config 方法来工作,但这很好用,读起来很自然
猜你喜欢
  • 2020-08-20
  • 2015-12-16
  • 2017-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-11
  • 2021-10-13
  • 1970-01-01
相关资源
最近更新 更多