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



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

我在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

回答"我该如何调试这样的东西?"

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

  2. 一个选项(对于任何卡住的unix二进制文件都很有用)是使用strace -p <PID>连接到进程。查看它可能被卡住的系统调用或系统调用循环。例如,一直在呼叫gettimeofday

  3. 要获得更详细的py.test输出,请安装pytest-suge。pip install pytest-sugar和用pytest.py --verbose . . .运行测试https://pypi.python.org/pypi/pytest-sugar

在测试使用SQLAlchemy的Flask应用程序时,我在pytest和Postgresql方面遇到了类似的问题。pytest似乎很难使用其带有Postgresql的request.addfinalizer方法来运行拆卸。

以前我有:

@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实例)但是,如果每次调用数据库fixture时都删除数据库:

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

那么pytest在第一次测试后就不会挂起了。

不知道代码中出现了什么问题,最好的方法是隔离失败的测试,并在其中设置断点进行查看。注意:我使用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

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

我遇到这个问题已经有很长一段时间了(尽管我没有使用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 --tracepytest --verbose也没有产生有用的信息

我最终不得不评论所有的内容,包括:

  1. 所有conftest.py代码和测试代码
  2. 慢慢取消注释/重新注释区域并确定根本原因
  3. 最终解决方案:使用工厂夹具添加终结器以调用__del__

在我的案例中,Flask应用程序没有检查if __name__ == '__main__':,所以它执行了app.start(),而这不是我的意图。

你可以在这里阅读更多详细信息。

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

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

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

修复者:

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

相关内容

  • 没有找到相关文章

最新更新