Pytest 在测试后花费的时间最多?

Posted

技术标签:

【中文标题】Pytest 在测试后花费的时间最多?【英文标题】:Pytest spending most time post-test? 【发布时间】:2021-02-28 20:01:51 【问题描述】:

我通过pytest 运行一个函数(在下面的示例中)需要 71 秒才能运行。但是,pytest 会多花 6 到 7 分钟做……某事。我可以从日志文件中看出预期的测试是在 7 分钟开始时执行的,但我无法想象之后会发生什么(如果相信“最慢持续时间”输出的话,显然这不是拆解)。

pytest 函数本身极小:

def test_preprocess_and_train_model():
    import my_module.pipeline as pipeline  # noqa

    pipeline.do_pipeline(do_s3_upload=False,
                         debug=True, update_params='tf_verbosity': 0)

如果我手动运行 test_preprocess_and_train_model()(例如,如果我通过解释器而不是通过 pytest 调用函数),大约需要 70 秒。

发生了什么,我该如何加快速度?

▶  pytest --version
pytest 6.2.2
▶ python --version
Python 3.8.5
▶ time pytest -k test_preprocess_and_train_model -vv --durations=0                                             
====================================================== test session starts =======================================================
platform darwin -- Python 3.8.5, pytest-6.2.2, py-1.9.0, pluggy-0.13.1 -- /usr/local/opt/python@3.8/bin/python3.8
cachedir: .pytest_cache
rootdir: /Users/blah_blah_blah/tests
collected 3 items / 2 deselected / 1 selected                                                                                    

test_pipelines.py::test_preprocess_and_train_model PASSED                                                                  [100%] 

======================================================== warnings summary ========================================================
test_pipelines.py::test_preprocess_and_train_model
  /Users/your_name_here/Library/Python/3.8/lib/python/site-packages/tensorflow/python/autograph/impl/api.py:22: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
    import imp

test_pipelines.py: 3604341 warnings
  sys:1: DeprecationWarning: PY_SSIZE_T_CLEAN will be required for '#' formats

test_pipelines.py::test_preprocess_and_train_model
  /Users/your_name_here/Library/Python/3.8/lib/python/site-packages/tensorflow/python/keras/engine/training.py:2325: UserWarning: `Model.state_updates` will be removed in a future version. This property should not be used in TensorFlow 2.0, as `updates` are applied automatically.
    warnings.warn('`Model.state_updates` will be removed in a future version. '

-- Docs: https://docs.pytest.org/en/stable/warnings.html
======================================================= slowest durations ========================================================
71.88s call     test_pipelines.py::test_preprocess_and_train_model
0.00s teardown test_pipelines.py::test_preprocess_and_train_model
0.00s setup    test_pipelines.py::test_preprocess_and_train_model
================================= 1 passed, 2 deselected, 3604343 warnings in 422.15s (0:07:02) ==================================
pytest -k test_preprocess_and_train_model -vv --durations=0  305.95s user 158.42s system 104% cpu 7:26.14 total

【问题讨论】:

你能发布被测代码和测试本身吗? 亲爱的@MarcelloRomani,测试本身只有一行,并调用了辅助脚本。不幸的是,我不能包含该代码(它是专有的),但这相当于训练 TensorFlow 模型并将一些数据上传到 S3。但是,如上面的输出所示,调用本身只有 71.88 秒。 我刚刚尝试抑制 S3 上传;问题仍然存在。 另外四个事实:首先,70 秒后,pytest 将“PASSED”打印到屏幕上。其次,在额外的 6 分钟内,pytest 将我的一个处理器保持在 100% 的 CPU 使用率。第三,我在 MacOS 11.2.2 上测试;在 Ubuntu 上运行,我没有观察到问题。第四,细心的读者可能会注意到上面的 360 万(!)错误信息;使用“--disable-warnings”运行不会改变任何东西。 在不向我们展示一些代码或可重现的示例的情况下,不确定有人可以如何帮助您。那时这只是一个猜谜游戏。 【参考方案1】:

我想我会发布这个解决方案,以防它帮助其他人。

theY4Kman 对代码进行分析的建议非常好。我自己的代码按预期在 70 秒内运行并干净地退出,但它产生了 360 万条警告消息。 pytest 中的每条警告消息都会触发一次 os.stat() 检查(以确定是哪一行代码产生了警告),评估 3.6M 系统调用需要 5 分钟左右。如果我在 pytest 的warnings.py 中注释掉了warning_record_to_str() 的核心,那么 pytest 大约需要 140 秒(即大部分问题都解决了)。

这也解释了为什么性能取决于平台(Mac 与 Ubuntu),因为错误消息的数量差异很大。

如果我理解正确的话,似乎有两个可悲的结论:

即使我使用--disable-warnings 标志,pytest 似乎也很乐意收集所有警告,统计它们等;它只是不打印它们。在我的例子中,这意味着 pytest 花费了 85% 的时间来计算它立即丢弃的信息。 os.stat() 检查发生在 Python 的 linecache.py 函数中。由于我收到了 360 万次相同的警告,我预计该函数将运行一次 os.stat() 并缓存结果,但这并没有发生。我想我只是误解了有关此功能的预期用途的一些基本内容。

【讨论】:

以上是关于Pytest 在测试后花费的时间最多?的主要内容,如果未能解决你的问题,请参考以下文章

技术干货 | pytest 自动化测试实战展示

pytest 运行命令

干货 | 一文搞定 pytest 自动化测试实战

Docker Pytest容器在完成测试过程后仍处于启动状态

pytest的基础(命名运行标签和断言)

pytest---分布式执行用例(pytest-xdist)