以下测试正常:
import pytest
from sqlalchemy import create_engine, text
from sqlalchemy.engine.url import URL
from sqlalchemy_utils import database_exists, create_database
@pytest.fixture()
def db_engine():
engine = create_engine(
URL('postgres',
username='postgres', password='postgres', database='my_database')
)
if not database_exists(engine.url):
create_database(engine.url)
return engine
def test_new_table_is_empty(db_engine):
try:
db_engine.execute(text('CREATE SCHEMA test_schema;'))
db_engine.execute(text('CREATE TABLE test_schema.new_table ();'))
result = db_engine.execute(text('SELECT * FROM test_schema.new_table;'))
assert result.rowcount == 0
finally:
try:
del result # The result would block the dropping of
# SCHEMA "test_schema" in the following cleanup.
except NameError:
pass
db_engine.execute(text('DROP SCHEMA IF EXISTS test_schema CASCADE;'))
但如果我将其设为失败,则将assert result.rowcount == 0
更改为assert result.rowcount == 1
,将无限期地挂在最后一行(架构所在的位置)被删除)甚至不能被[ Ctrl + c ]中止。我必须kill
py.test
进程(或python
进程,具体取决于我调用测试运行器的方式)来终止它。 (如果我追加
if __name__ == "__main__":
test_new_table_is_empty(db_engine())
并将文件作为普通的python脚本而不是py.test
运行,我得到预期的AssertionError
。)
但是,如果我只是用assert False
替换断言(并再次使用py.test
运行),那么测试套装将按照预期完成一次失败的测试。因此,我假设如果断言失败,pytest将保留对result
的引用,可能是因为它与堆栈跟踪一起显示的错误分析。 是这样的吗?
我怎样才能也应该避免阻塞?我是否应该只对结果中提取的数据而不是ResultProxy
本身的属性进行测试断言?
答案 0 :(得分:2)
呼叫
result.close()
而不是
del result
我认为如果断言失败,pytest会保留对
result
的引用,可能是因为它与堆栈跟踪一起显示的错误分析。 是这样的吗?
这仍然是我的工作假设。如果有人知道的话,请赐教。
我该如何避免阻止?
而不是del
ResultProxy
result
,而是在finally
子句中明确close()
:
def test_new_table_is_empty(db_engine):
try:
db_engine.execute(text('CREATE SCHEMA test_schema;'))
db_engine.execute(text('CREATE TABLE test_schema.new_table ();'))
result = db_engine.execute(text('SELECT * FROM test_schema.new_table;'))
assert result.rowcount == 0
finally:
try:
result.close() # Release row and table locks.
except NameError:
pass
db_engine.execute(text('DROP SCHEMA IF EXISTS test_schema CASCADE;'))
这将release result
所持有的所有行和表锁。
要避免嵌套将嵌套的try
子句的混乱try
子句的混乱移动到其他地方,您可以使用with contextlib.closing(...):
:
from contextlib import closing
# ...
def test_new_table_is_empty(db_engine):
try:
db_engine.execute(text('CREATE SCHEMA test_schema;'))
db_engine.execute(text('CREATE TABLE test_schema.new_table ();'))
with closing(
db_engine.execute(text('SELECT * FROM test_schema.new_table;'))
) as result:
assert result.rowcount == 0
finally:
db_engine.execute(text('DROP SCHEMA IF EXISTS test_schema CASCADE;'))
我是否只应对从结果中获取的数据而不是
ResultProxy
本身的属性进行测试断言?
只有在您获取所有行时才会有效,从而耗尽ResultProxy
,这会隐含_soft_close()
它。如果结果(可能意外地)有更多行而不是您获取,则结果将保持打开并继续保持锁定,以防止执行以下清理。
由于您只对测试中的行数而不是实际结果的内容感兴趣,因此明确关闭是获取您不会使用的结果的最佳选择,除非可能用于计数他们或计算他们的长度。