我有一个同时使用setUp
和tearDown
方法的测试用例:
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
开头的行)不会调用任何tearDown
行。甚至没有显示post tearDown 0
消息!
我现在已经将错误追溯到使用self.assertRaisesRegEx
而不是self.assertRaisesRegExp
,因此异常会在 unit-test 中引发,而不是在测试代码内部!< / p>
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
,而不是在我的生产代码中调用?
我会继续调查......
答案 0 :(得分:1)
如果您怀疑未调用tearDown
,那么我可以建议您在测试中使用上下文管理器进行资源分配。 with
语句保证如果__enter__()
方法返回时没有错误,则始终会调用__exit__()
。
以下是修改了使用上下文管理器进行连接分配的示例:
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()