pytest: 测试之间进行完全清理

6
在一个模块中,我有两个测试:
@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

案例一

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

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)之间是否发生了某些事情,而在同一“pytest进程”中从test_1test_2的调用(情况2)之间没有发生,这能解释为什么“情况1”正常工作,而“情况2”在test_1test_2之间卡住了吗?如果是这样,有办法在“情况2”中强制执行与 test_1test_2 之间的相同“清理”过程吗?

注意:我已经尝试将“myfixture”的作用域指定为“function”,并且还仔细检查了“clean_stuff”在“case 2”中也是在“test_1”之后被调用。


4
你的prepare_stuff/clean_stuff中存在一些错误/死锁/全局状态污染,因此这个问题无法回答。 - anthony sottile
你能详细说明一下 some_code() 函数中正在发生什么吗?这样我们才能回答你的问题。 - Taras
3个回答

1

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

0

很可能是在您的prepare_stuff和/或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


-1

一定是在prepare_stuffclean_stuff或者somecode中出了问题,因为如果你用虚拟代码替换这些方法,它就能正常工作!

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) 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接