当 py.test 静默挂起时怎么办?

问题描述 投票:0回答:8

在使用 py.test 时,我有一些测试在 SQLite 上运行良好,但当我切换到 Postgresql 时会静默挂起。我将如何去调试这样的东西?是否有我可以运行测试或设置断点的“详细”模式?更一般地说,当 pytest 静默停止时,标准的攻击计划是什么?我试过使用 pytest-timeout,并使用 $ py.test --timeout=300 运行测试,但测试仍然挂起,屏幕上没有任何活动

sqlite postgresql timeout freeze pytest
8个回答
30
投票

我遇到了与 Flask 和 SQLAlchemy 相同的 SQLite/Postgres 问题,类似于 Gordon Fierce。但是,我的解决方案不同。 Postgres 对表锁和连接很严格,所以在拆卸时明确关闭会话连接解决了我的问题。

我的工作代码:

@pytest.yield_fixture(scope='function')
def db(app):
    # app is an instance of a flask app, _db a SQLAlchemy DB
    _db.app = app
    with app.app_context():
        _db.create_all()

    yield _db

    # Explicitly close DB connection
    _db.session.close()

    _db.drop_all()

参考资料:SQLAlchemy


13
投票

回答“我将如何调试这样的东西?”这个问题

  1. 运行 py.test -m trace --trace 以获取 python 调用的跟踪。

  2. 一个选项(对任何卡住的 unix 二进制文件有用)是使用

    strace -p <PID>
    附加到进程。查看它可能卡在哪个系统调用上或系统调用循环。例如卡住调用 gettimeofday

  3. 要获得更详细的 py.test 输出,请安装 pytest-sugar。

    pip install pytest-sugar
    并使用
    pytest.py --verbose . . .
    运行测试 https://pypi.python.org/pypi/pytest-sugar


9
投票

我在测试使用 SQLAlchemy 的 Flask 应用程序时遇到了与 pytest 和 Postgresql 类似的问题。 pytest 似乎很难使用它的 request.addfinalizer 方法和 Postgresql 进行拆解。

以前我有:

@pytest.fixture
def db(app, request):
    def teardown():
        _db.drop_all()

    _db.app = app
    _db.create_all()

    request.addfinalizer(teardown)

    return _db

(_db 是我从 extensions.py 导入的 SQLAlchemy 实例) 但是如果我每次调用数据库夹具时都删除数据库:

@pytest.fixture
def db(app, request):
    _db.app = app
    _db.drop_all()
    _db.create_all()
    return _db

然后 pytest 不会在你第一次测试后挂起。


5
投票

不知道代码中有什么问题,最好的方法是隔离失败的测试并在其中设置断点看看。注意:我使用 pudb 而不是 pdb,因为如果您不使用 IDE,它确实是调试 python 的最佳方式。

例如,您可以在测试文件中添加以下内容:

import pudb
...

def test_create_product(session):
    pudb.set_trace()
    # Create the Product instance
    # Create a  Price instance
    # Add the Product instance to the session. 
    ...

然后运行它

py.test -s --capture=no test_my_stuff.py

现在您将能够准确地看到脚本锁定的位置,并在这个特定的执行时刻检查堆栈和数据库。否则就像大海捞针。


2
投票

我刚遇到这个问题有一段时间了(虽然我没有使用 SQLite)。测试套件在本地运行良好,但在 CircleCI(Docker)中失败。

我的问题最终是:

  1. 对象的底层实现使用线程
  2. 对象的
    __del__
    通常会结束线程
  3. 我的测试套件没有像它应该的那样调用
    __del__

我想我会添加我是如何想出来的。其他答案建议这些:

  1. 发现
    pytest-timeout
    的用法没有帮助,测试在完成后挂起
    • 通过
      pytest --timeout 5
    • 调用
    • 版本:
      pytest==6.2.2, pytest-timeout==1.4.2
  2. 运行
    pytest -m trace --trace
    pytest --verbose
    也没有产生有用的信息

我最终不得不对所有内容进行评论,包括:

  1. 所有
    conftest.py
    代码和测试代码
  2. 慢慢取消注释/重新注释区域并确定根本原因
  3. 终极解决方案:使用factory fixture添加finalizer来调用
    __del__

1
投票

在我的例子中,Flask 应用程序没有检查

if __name__ == '__main__':
所以它执行了
app.start()
而这不是我的意图。

您可以阅读更多详细信息here.


0
投票

在我的例子中,当断言失败时,diff 在比较 4 MB 数据时工作得非常慢。

with open(path, 'rb') as f:
    assert f.read() == data

固定者:

with open(path, 'rb') as f:
    eq = f.read() == data
    assert eq

0
投票

对我来说,摆脱挂起测试的解决方案是使用 pytest 插件 pytest-xdist(并并行运行测试)。我不确定为什么会解决它。原因可能是插件在(多个)线程中运行测试。

© www.soinside.com 2019 - 2024. All rights reserved.