Python 如何确保使用nosetest调用tearDown(在测试中出现未捕获异常的情况下)?
我有一个带有Python 如何确保使用nosetest调用tearDown(在测试中出现未捕获异常的情况下)?,python,unit-testing,sqlalchemy,Python,Unit Testing,Sqlalchemy,我有一个带有设置和拆卸方法的测试用例: TESTCONF = SafeConfigParser(...) ENGINE = create_engine(TESTCONF.get('database', 'dsn')) class TestBase(TestCase): def setUp(self): self.config = TESTCONF self.connection = ENGINE.connect() self.trans
设置
和拆卸
方法的测试用例:
TESTCONF = SafeConfigParser(...)
ENGINE = create_engine(TESTCONF.get('database', 'dsn'))
class TestBase(TestCase):
def setUp(self):
self.config = TESTCONF
self.connection = ENGINE.connect()
self.trans = self.connection.begin()
self.session = Session(bind=self.connection)
def tearDown(self):
print "post teardown 0", ENGINE.pool.status()
self.trans.rollback()
print "post teardown 1", ENGINE.pool.status()
self.session.close()
print "post teardown 2", ENGINE.pool.status()
self.connection.close()
print "post teardown 3", ENGINE.pool.status(), "\n"
所有与DB相关的测试用例都继承自此类。似乎并不总是调用tearDown
。我很难定位错误。在某一点上,测试运行程序挂起
self.connection = ENGINE.connect()
我假设并不总是调用close
方法来释放池中的连接
你知道要找什么吗
更新:我如何添加了一些打印语句(在上面的示例代码中也添加了它们),我最初的想法是正确的。某些连接未正确关闭,也未返回池。测试中的所有“错误”(而不是“失败”)都会发生这种情况。下面的代码块显示了我使用上述tearDown
方法得到的输出(为了简洁起见,提前切断)。如您所见,有错误的行(那些以Epre
而不是.pre
开头的行)不调用任何拆卸
行。甚至没有显示post-tearDown 0
消息
我现在已经将错误追溯到使用self.assertRaisesRegEx
而不是self.assertRaisesRegExp
,因此异常是在单元测试中引发的,而不是在测试代码中
pre setup Pool size: 5 Connections in pool: 0 Current Overflow: -5 Current Checked out connections: 0
post connect Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 0 Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 1 Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 2 Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 3 Pool size: 5 Connections in pool: 1 Current Overflow: -4 Current Checked out connections: 0
.pre setup Pool size: 5 Connections in pool: 1 Current Overflow: -4 Current Checked out connections: 0
post connect Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 0 Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 1 Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 2 Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 3 Pool size: 5 Connections in pool: 1 Current Overflow: -4 Current Checked out connections: 0
.pre setup Pool size: 5 Connections in pool: 1 Current Overflow: -4 Current Checked out connections: 0
post connect Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 0 Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 1 Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 2 Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 3 Pool size: 5 Connections in pool: 1 Current Overflow: -4 Current Checked out connections: 0
.pre setup Pool size: 5 Connections in pool: 1 Current Overflow: -4 Current Checked out connections: 0
post connect Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
'TestCommonBase' object has no attribute 'assertRaisesRegex'
post teardown 0 Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 1 Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 2 Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 3 Pool size: 5 Connections in pool: 1 Current Overflow: -4 Current Checked out connections: 0
.pre setup Pool size: 5 Connections in pool: 1 Current Overflow: -4 Current Checked out connections: 0
post connect Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 0 Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 1 Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 2 Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 3 Pool size: 5 Connections in pool: 1 Current Overflow: -4 Current Checked out connections: 0
.pre setup Pool size: 5 Connections in pool: 1 Current Overflow: -4 Current Checked out connections: 0
post connect Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 0 Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 1 Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 2 Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 3 Pool size: 5 Connections in pool: 1 Current Overflow: -4 Current Checked out connections: 0
.pre setup Pool size: 5 Connections in pool: 1 Current Overflow: -4 Current Checked out connections: 0
post connect Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 0 Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 1 Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 2 Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 3 Pool size: 5 Connections in pool: 1 Current Overflow: -4 Current Checked out connections: 0
.pre setup Pool size: 5 Connections in pool: 1 Current Overflow: -4 Current Checked out connections: 0
post connect Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
'TestCommonBase' object has no attribute 'assertRaisesRegex'
post teardown 0 Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 1 Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 2 Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 3 Pool size: 5 Connections in pool: 1 Current Overflow: -4 Current Checked out connections: 0
.pre setup Pool size: 5 Connections in pool: 1 Current Overflow: -4 Current Checked out connections: 0
post connect Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 0 Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 1 Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 2 Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 3 Pool size: 5 Connections in pool: 1 Current Overflow: -4 Current Checked out connections: 0
.pre setup Pool size: 5 Connections in pool: 1 Current Overflow: -4 Current Checked out connections: 0
post connect Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 0 Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 1 Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 2 Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post teardown 3 Pool size: 5 Connections in pool: 1 Current Overflow: -4 Current Checked out connections: 0
.SSpre setup Pool size: 5 Connections in pool: 1 Current Overflow: -4 Current Checked out connections: 0
post connect Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
ESpre setup Pool size: 5 Connections in pool: 0 Current Overflow: -4 Current Checked out connections: 1
post connect Pool size: 5 Connections in pool: 0 Current Overflow: -3 Current Checked out connections: 2
Epre setup Pool size: 5 Connections in pool: 0 Current Overflow: -3 Current Checked out connections: 2
post connect Pool size: 5 Connections in pool: 0 Current Overflow: -2 Current Checked out connections: 3
Epre setup Pool size: 5 Connections in pool: 0 Current Overflow: -2 Current Checked out connections: 3
post connect Pool size: 5 Connections in pool: 0 Current Overflow: -1 Current Checked out connections: 4
Epre setup Pool size: 5 Connections in pool: 0 Current Overflow: -1 Current Checked out connections: 4
post connect Pool size: 5 Connections in pool: 0 Current Overflow: 0 Current Checked out connections: 5
Epre setup Pool size: 5 Connections in pool: 0 Current Overflow: 0 Current Checked out connections: 5
post connect Pool size: 5 Connections in pool: 0 Current Overflow: 1 Current Checked out connections: 6
Epre setup Pool size: 5 Connections in pool: 0 Current Overflow: 1 Current Checked out connections: 6
post connect Pool size: 5 Connections in pool: 0 Current Overflow: 2 Current Checked out connections: 7
Epre setup Pool size: 5 Connections in pool: 0 Current Overflow: 2 Current Checked out connections: 7
post connect Pool size: 5 Connections in pool: 0 Current Overflow: 3 Current Checked out connections: 8
Epre setup Pool size: 5 Connections in pool: 0 Current Overflow: 3 Current Checked out connections: 8
post connect Pool size: 5 Connections in pool: 0 Current Overflow: 4 Current Checked out connections: 9
Epre setup Pool size: 5 Connections in pool: 0 Current Overflow: 4 Current Checked out connections: 9
post connect Pool size: 5 Connections in pool: 0 Current Overflow: 5 Current Checked out connections: 10
Epre setup Pool size: 5 Connections in pool: 0 Current Overflow: 5 Current Checked out connections: 10
post connect Pool size: 5 Connections in pool: 0 Current Overflow: 6 Current Checked out connections: 11
Epre setup Pool size: 5 Connections in pool: 0 Current Overflow: 6 Current Checked out connections: 11
post connect Pool size: 5 Connections in pool: 0 Current Overflow: 7 Current Checked out connections: 12
Epre setup Pool size: 5 Connections in pool: 0 Current Overflow: 7 Current Checked out connections: 12
post connect Pool size: 5 Connections in pool: 0 Current Overflow: 8 Current Checked out connections: 13
Epre setup Pool size: 5 Connections in pool: 0 Current Overflow: 8 Current Checked out connections: 13
post connect Pool size: 5 Connections in pool: 0 Current Overflow: 9 Current Checked out connections: 14
Epre setup Pool size: 5 Connections in pool: 0 Current Overflow: 9 Current Checked out connections: 14
post connect Pool size: 5 Connections in pool: 0 Current Overflow: 10 Current Checked out connections: 15
post teardown 0 Pool size: 5 Connections in pool: 0 Current Overflow: 10 Current Checked out connections: 15
post teardown 1 Pool size: 5 Connections in pool: 0 Current Overflow: 10 Current Checked out connections: 15
post teardown 2 Pool size: 5 Connections in pool: 0 Current Overflow: 10 Current Checked out connections: 15
post teardown 3 Pool size: 5 Connections in pool: 1 Current Overflow: 10 Current Checked out connections: 14
.pre setup Pool size: 5 Connections in pool: 1 Current Overflow: 10 Current Checked out connections: 14
post connect Pool size: 5 Connections in pool: 0 Current Overflow: 10 Current Checked out connections: 15
Epost teardown 0 Pool size: 5 Connections in pool: 0 Current Overflow: 10 Current Checked out connections: 15
post teardown 1 Pool size: 5 Connections in pool: 0 Current Overflow: 10 Current Checked out connections: 15
post teardown 2 Pool size: 5 Connections in pool: 0 Current Overflow: 10 Current Checked out connections: 15
post teardown 3 Pool size: 5 Connections in pool: 1 Current Overflow: 10 Current Checked out connections: 14
其他详情:
为了回答这个问题,我写了一个很小的可复制的例子。不幸的是,一个人没有表现出这种行为:
class MyTest(TestCase):
"""
Example test case meant to demonstrate that ``tearDown`` is not called.
It turns out, in this case, ``tearDown`` *is* called as expected!
"""
def setUp(self):
print "setup"
def tearDown(self):
print "tearDown"
def test_failing(self):
print int('yes')
if __name__ == '__main__':
main()
那么,是什么使这个示例与我的实际代码不同呢?为什么在这个简单的示例中调用了tearDown
,而在我的生产代码中没有调用
我将继续调查…如果您怀疑没有调用
tearDown
,那么我可以建议您在测试中使用上下文管理器进行资源分配。with
语句保证如果\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu()方法返回时没有错误,那么将始终调用\uuuuuuuuuuuuuuuuuuuuuuuuu
下面是您修改为使用上下文管理器进行连接分配的示例:
TESTCONF = SafeConfigParser(...)
ENGINE = create_engine(TESTCONF.get('database', 'dsn'))
class DBConnection(object):
def __init__(self, engine):
self.engine = engine
def __enter__(self):
self.connection = engine.connect()
self.trans = self.connection.begin()
self.session = Session(bind=self.connection)
# return value can be accessed using `as` directive
return self.connection, self.trans, self.session
def __exit__(self, exc_type, exc_val, traceback):
self.trans.rollback()
self.session.close()
self.connection.close()
class TestBase(unittest.TestCase):
def setUp(self):
self.config = TESTCONF
def run(self, result=None):
with DBConnection(ENGINE) as db_conn:
self.connection, self.trans, self.session = db_conn
super(MyTest, self).run(result)
如果DBConnection类看起来太庞大,也可以使用contextlib:
from contextlib import contextmanager
@contextmanager
def DBConnection(engine):
connection = engine.connect()
trans = connection.begin()
session = Session(bind=connection)
yield connection, trans, session
trans.close()
session.close()
connection.close()
看来你在这里做了很多假设。到底是什么让你认为拆卸没有被调用?如果你把一个print语句放在“tearDown”方法中,或者其他一些很容易被识别为已运行的语句(比如写入文件),你会看到该语句吗?@MarkHildreth对不起,我不得不匆忙地写下这个问题(赶火车)。我试过打印一份声明。我没有看到输出。一旦我回到办公室,我会尝试写一个文件。Nosetests拦截stdout,因此在这种情况下,打印可能不是一种可靠的调试技术。@MarkHildreth我现在有更多的时间进行调查,并为问题添加了更多细节。我仍然很困惑为什么会发生这种情况。我将尝试写一个独立的例子来重现这种行为。但“简单”的演示代码似乎不足以触发错误:(这是一个有趣的想法。我会尝试一下。但最让我担心的是,tearDown
无论如何都应该被调用。使用上下文管理器似乎是多余的。但值得一试。仅供参考:我还没有尝试过你的解决方案,但同时为有关我的发现的问题添加了更多细节。嗯,在我现在正在使用你的解决方案,无所事事,一事无成。几天后我会接受。我也在给其他人一个插话的机会。你好,我是过去的:)使用@contextmanager
的解决方案是干净的,但它也将无法正确关闭会话,除非在yield
语句周围添加try/finally
块。并关闭该finally
块中的对象!