pytest:测试之间的完全清理

pytest: full cleanup between tests

在一个模块中,我有两个测试:

@pytest.fixture
def myfixture(request):
    prepare_stuff()
    yield 1
    clean_stuff()
    # time.sleep(10) # in doubt, I tried that, did not help

def test_1(myfixture):
    a = somecode()
    assert a==1

def test_2(myfixture):
    b = somecode()
    assert b==1

案例 1

当这两个测试单独执行时,一切正常,即两者

pytest ./test_module.py:test_1

紧接着:

pytest ./test_module.py:test_2

运行直到完成并成功通过。

案例 2

但是:

pytest ./test_module.py -k "test_1 or test_2"

报告:

collected 2 items
test_module.py .

并永远挂起(调查后:test_1 成功完成,但第二次调用 prepare_stuff 挂起)。

问题

在我的特定设置中,prepare_stuffclean_stuffsomecode 已经相当先进,即它们创建和删除一些共享内存段,如果操作不当,可能会导致一些挂起。所以这里可能会出现一些问题。

但我的问题是:在 pytest 的两次调用(情况 1)之间是否发生了某些事情,而这些事情不会发生在来自同一个 test_1test_2 的调用之间? pytest 过程”(案例 2),这可以解释为什么“案例 1”工作正常而“案例 2”挂在 test_1test_2 之间?如果是这样,对于“案例 2”,有没有办法“强制”在 test_1test_2 之间发生相同的“清理”?

注意:我已经尝试将“myfixture”的范围指定为“function”,并且还仔细检查了“clean_stuff”是在“test_1”之后调用的,即使在“case”中也是如此2".

myfixture 保证 cleanup() 的当前结构在 test_1test_2 之间调用,除非 prepare_stuff() 引发未处理的异常。您可能会注意到这一点,所以最有可能的问题是 cleanup() 没有“清理” prepare_stuff() 所做的一切,因此 prepare_stuff() 无法再次设置。

至于您的问题,没有任何 pytest 相关的问题会导致测试之间的挂起。您可以通过添加 finalizer 强制调用 cleanup()(即使引发异常),它将在拆解部分

之后调用
@pytest.fixture
def myfixture(request):
    request.addfinalizer(cleanup)
    prepare_stuff()
    yield 1

它必须是 prepare_stuffclean_stuffsomecode 上的内容,因为如果您用伪代码替换这些方法,它就可以工作!

def prepare_stuff():
    logging.warning("prepare_stuff()")

def clean_stuff():
    logging.warning("clean_stuff()")

def somecode():
    logging.warning("somecode()")
    return 0
/tmp/tmp.JOfTxVUv1z via  v3.8.10 (.env) 
❯ pytest ./test_module.py -k "test_1 or test_2"
============================= test session starts ==============================
platform linux -- Python 3.8.10, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
rootdir: /tmp/tmp.JOfTxVUv1z
collected 2 items                                                              

test_module.py FF                                                        [100%]

=================================== FAILURES ===================================
____________________________________ test_1 ____________________________________

myfixture = 1

    def test_1(myfixture):
        a = somecode()
>       assert a==1
E       assert 0 == 1

test_module.py:25: AssertionError
------------------------------ Captured log setup ------------------------------
WARNING  root:test_module.py:5 prepare_stuff()
------------------------------ Captured log call -------------------------------
WARNING  root:test_module.py:13 somecode()
---------------------------- Captured log teardown -----------------------------
WARNING  root:test_module.py:9 clean_stuff()
____________________________________ test_2 ____________________________________

myfixture = 1

    def test_2(myfixture):
        b = somecode()
>       assert b==1
E       assert 0 == 1

test_module.py:29: AssertionError
------------------------------ Captured log setup ------------------------------
WARNING  root:test_module.py:5 prepare_stuff()
------------------------------ Captured log call -------------------------------
WARNING  root:test_module.py:13 somecode()
---------------------------- Captured log teardown -----------------------------
WARNING  root:test_module.py:9 clean_stuff()
=========================== short test summary info ============================
FAILED test_module.py::test_1 - assert 0 == 1
FAILED test_module.py::test_2 - assert 0 == 1
============================== 2 failed in 0.03s ===============================

/tmp/tmp.JOfTxVUv1z via  v3.8.10 (.env) 

您的 prepare_stuff and/or clean_stuff 函数中可能发生了某些事情。当您 运行 测试为:

pytest ./test_module.py -k "test_1 or test_2"

它们 运行 在相同的执行上下文、相同的进程等中运行。因此,例如,如果 clean_stuff 没有进行适当的清理,则执行下一个测试会失败。当您 运行 测试为:

pytest ./test_module.py:test_1
pytest ./test_module.py:test_2

它们 运行 在不同的执行上下文中运行,即它们在绝对干净的环境中启动,并且,除非您要修改一些外部资源,否则在这种情况下您可以轻松删除 clean_stuff他们无论如何都会过去。

要排除 pytest 问题,只需尝试 运行:

    prepare_stuff()

    a = somecode()
    assert a==1

    clean_stuff()

    prepare_stuff()

    b = somecode()
    assert b==1

    clean_stuff()

我很确定你会遇到同样的问题,这将确认问题出在你的代码中,而不是在 pytest