Python [求助帖] Pytest 在 rerun 失败的用例时, setup/teardown 打印的次数异常。

Duke · 2022年05月26日 · 最后由 Thirty-Thirty 回复于 2022年06月02日 · 6473 次阅读

写在前面:
程序:

import pytest
import time
class TestClass_10000():
    def setup_method(self):
        print ("setup ---->")

    def teardown_method(self):
        print ("teardown ---->")

    def test_one(self):
        print ("here is test_one")
        assert 1 == 2

在终端执行的命令:
pytest test_collection/test_collection01/test_01.py::TestClass_10000::test_one --html report.html --reruns 1
测试平台信息:
Packages {"pluggy": "1.0.0", "py": "1.11.0", "pytest": "7.1.2"}
Platform macOS-10.16-x86_64-i386-64bit
Plugins {"forked": "1.4.0", "html": "3.1.1", "metadata": "2.0.1", "parallel": "0.0.10", "rerunfailures": "10.2", "xdist": "2.5.0"}
Python 3.9.1
输出的报告:

预期实现的场景:
测试用例在执行前会输出一次"setup",执行过程中输出一次"here is test_one",执行结束输出一次"teardown"。 测试用例失败,重新执行一次测试用例,测试用例在执行前会输出一次"setup",执行过程中输出一次"here is test_one",执行结束输出一次"teardown"。

按照预期,报告应该是:
Failed:
setup-->
here is test_one
teardown-->
Rerun:
setup -->
here is test_one
teardown-->
疑惑的地方:

  1. 为什么最终报告里面, Failed 中 "setup" + "here is test_one" + "teardown" 打印了 2 次?
  2. 为什么最终报告里面, Rerun 中只有 "setup" + "here is test_one", 那 "teardown" 哪里去了呢?

恳请各位路过的大神,慷慨解囊,提供宝贵意见。

共收到 5 条回复 时间 点赞

好问题,本地试了一下,确实有这个情况存在,而且命令行输出只会有第二个问题,不会有第一个问题:

pytest t.py::TestClass_10000::test_one --html report.html --reruns 1
=========================================================================================================== test session starts ===========================================================================================================
platform darwin -- Python 3.9.2, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
rootdir: /Users/chenhengjie/Documents/Projects/质效改进组/qa_repos/tmp/python_scripts
plugins: metadata-2.0.1, rerunfailures-10.2, html-3.1.1
collected 1 item                                                                                                                                                                                                                          

t.py R                                                                                                                                                                                                                              [100%]F [100%]

================================================================================================================ FAILURES =================================================================================================================
________________________________________________________________________________________________________ TestClass_10000.test_one _________________________________________________________________________________________________________

self = <python_scripts.t.TestClass_10000 object at 0x101d2d640>

    def test_one(self):
        print ("here is test_one")
>       assert 1 == 2
E       assert 1 == 2

t.py:14: AssertionError
---------------------------------------------------------------------------------------------------------- Captured stdout setup ----------------------------------------------------------------------------------------------------------
setup ---->
---------------------------------------------------------------------------------------------------------- Captured stdout call -----------------------------------------------------------------------------------------------------------
here is test_one
-------------------------------------------------------------------------------------------------------- Captured stdout teardown ---------------------------------------------------------------------------------------------------------
teardown ---->
---------------------------------------------------------------------------------------------------------- Captured stdout setup ----------------------------------------------------------------------------------------------------------
setup ---->
---------------------------------------------------------------------------------------------------------- Captured stdout call -----------------------------------------------------------------------------------------------------------
here is test_one
------------------------------------------------------------- generated html file: file:///Users/chenhengjie/Documents/Projects/质效改进组/qa_repos/tmp/python_scripts/report.html -------------------------------------------------------------
========================================================================================================= short test summary info =========================================================================================================
FAILED t.py::TestClass_10000::test_one - assert 1 == 2
======================================================================================================= 1 failed, 1 rerun in 0.13s =====================================================

从上面输出看,可以基本猜测下两个问题的原因:

1、出现了两次 setup 、teardown ——应该是 html 插件的问题
2、重跑时没有跑 teardown ——应该是重跑插件 runfailtures 的问题

这些问题都是比较细节的问题,推荐你直接看下这些插件的源码逻辑来解析,也有助于你更深入了解 pytest 的机制。时间有限我就没法去细看源码了。

Duke #2 · 2022年05月27日 Author
陈恒捷 回复

感谢您的答复。
第一个问题其实是在查看 report.html 的时候发现的,您通过浏览器打开 report.html, 看到 Failed 的那条结果,然后点击"show details"就能发现,打印出了 2 次。 这个地方, 终端输出的确是 1 次, 但是不知道为什么 Failed 结果中却记录了 2 次。 我尝试下看看源码,是否能看懂吧,哈哈~

我这边也试了下。预料之中的是,rerun 时 teardown 运行了。预料之外的是,运行次数多于设置重跑次数。

(venv) C:\Users\Administrator\PycharmProjects\untitled1>pytest testauto.py --reruns 2
================================================================================================= test session starts ==================================================================================================
platform win32 -- Python 3.7.2, pytest-7.1.2, pluggy-1.0.0
rootdir: C:\Users\Administrator\PycharmProjects\untitled1
plugins: rerunfailures-10.2
collected 1 item                                                                                                                                                                                                        

testauto.py R                                                                                                                                                                                                     [100%]R
 [100%]F [100%]

======================================================================================================= FAILURES =======================================================================================================
____________________________________________________________________________________________________ Test1.test_one ____________________________________________________________________________________________________

self = <testauto.Test1 object at 0x0000000003CE9940>

    def test_one(self):
        print("here is test_one")
>       assert 1 == 2
E       assert 1 == 2

testauto.py:10: AssertionError
------------------------------------------------------------------------------------------------ Captured stdout setup -------------------------------------------------------------------------------------------------
setup ---->
------------------------------------------------------------------------------------------------- Captured stdout call -------------------------------------------------------------------------------------------------
here is test_one
----------------------------------------------------------------------------------------------- Captured stdout teardown -----------------------------------------------------------------------------------------------
teardown ---->
------------------------------------------------------------------------------------------------ Captured stdout setup -------------------------------------------------------------------------------------------------
setup ---->
------------------------------------------------------------------------------------------------- Captured stdout call -------------------------------------------------------------------------------------------------
here is test_one
----------------------------------------------------------------------------------------------- Captured stdout teardown -----------------------------------------------------------------------------------------------
teardown ---->
------------------------------------------------------------------------------------------------ Captured stdout setup -------------------------------------------------------------------------------------------------
setup ---->
------------------------------------------------------------------------------------------------- Captured stdout call -------------------------------------------------------------------------------------------------
here is test_one
----------------------------------------------------------------------------------------------- Captured stdout teardown -----------------------------------------------------------------------------------------------
teardown ---->
----------------------------------------------------------------------------------------------- Captured stdout teardown -----------------------------------------------------------------------------------------------
teardown ---->
----------------------------------------------------------------------------------------------- Captured stdout teardown -----------------------------------------------------------------------------------------------
teardown ---->
=============================================================================================== short test summary info ================================================================================================
FAILED testauto.py::Test1::test_one - assert 1 == 2
============================================================================================== 1 failed, 2 rerun in 0.06s ==============================================================================================


Duke #2 · 2022年05月30日 Author

teardown 这个问题, 在终端显示是没问题的, 您需要用到 pytest-html, 查看 这个插件生成出来的 html 文件。
您说的 “运行次数多余设置重跑次数” 是什么意思吖, 从 short summary 里看 , 程序的确是 rerun 了 2 次吖 ~

Duke 回复

设置重跑次数是 2,teardown 预期调用次数是 3,而实际调用次数是 5

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册