ERROR at teardown of test_create_user File "tests/conftest.py", line 40, in db_session session.rollback() sqlalchemy.exc.PendingRollbackError: 由于 flush 期间之前的异常,此 Session 的事务已被回滚。
ERROR at teardown of test_create_user File "tests/conftest.py", line 40, in db_session session.rollback() sqlalchemy.exc.PendingRollbackError: This Session's transaction has been rolled back due to a previous exception during flush.
ID: python/pytest-teardown-error-masked
版本兼容性
| 版本 | 状态 | 引入 | 弃用 | 备注 |
|---|---|---|---|---|
| 2.0 | active | — | — | — |
根因分析
测试使 SQLAlchemy session 处于失败状态(flush 期间未处理异常);fixture 清理时对已失效的 session 调用 rollback/close,产生 teardown ERROR 掩盖了原始失败。
English
The test left the SQLAlchemy session in a failed state (unhandled exception during flush); the fixture teardown then calls rollback/close on a session that is already invalid, producing a teardown ERROR that masks the original failure.
解决方案
-
90% 成功率
Use a nested transaction + savepoint pattern and always roll back cleanly: @pytest.fixture def db_session(engine): conn = engine.connect() trans = conn.begin() session = Session(bind=conn) try: yield session finally: session.close() trans.rollback() conn.close() -
85% 成功率
Or use `session.begin_nested()` and explicitly rollback the savepoint: @pytest.fixture def db_session(engine): session = Session(bind=engine) session.begin_nested() yield session session.rollback() session.close()
无效尝试
常见但无效的做法:
-
85% 失败
Hides the real error and leaves the session dirty, cascading failures into later tests.
-
70% 失败
Does not clear the failed transaction state; rollback still raises.