我使用setup和teardown方法进行单元测试,如下所示:
def setUp(self):
self.foo = "bar"
self.bar = "foo"
def tearDown(self):
del self.foo
del self.bar
在__del__
中实例化的每个对象上是否有更简洁的方法来调用setUp
?如果我不这样做,那么在setUp
中打开的MySQL数据库的连接(通过实例化这些对象)似乎在每次测试后都保持打开状态。
理想情况我当然会找出潜在的问题(为什么在测试完成并且测试用例被丢弃时,这些数据库连接没有被关闭)。与此同时,有del
所有这些对象的清洁方式吗?
使用MySQLdb
库创建数据库连接,还有一个析构函数来关闭连接:
class Foo(object):
def __init__(self,some_credentials):
self.db_connection = MySQLdb.connect(some_credentials)
def __del__(self):
self.db_connection.close()
答案 0 :(得分:8)
这里的根本问题是每个python单元测试在每个测试用例运行后都不会丢弃测试实例。实例保存在内存中,因此分配给self的任何对象也会保留在内存中,直到整个套件完成。
您可以使用以下代码重现此内容。每次运行的附加测试都会增加内存使用量。如果self.large_list
中的None
设置为teardown
,则内存使用率保持一致。
import resource
import unittest
import uuid
class TestSelfGarbageCollection(unittest.TestCase):
def setUp(self):
# Create an object that will use lots of memory
self.large_list = []
for _ in range(300000):
self.large_list.append(uuid.uuid4())
def tearDown(self):
# Without the following line a copy of large_list will be kept in
# memory for each test that runs, uncomment the line to allow the
# large_list to be garbage collected.
# self.large_list = None
mb_memory = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss / 1000
print("Memory usage: %s MB" % mb_memory)
def test_memory1(self):
pass
def test_memory2(self):
pass
def test_memory3(self):
pass
def test_memory4(self):
pass
def test_memory5(self):
pass
使用以下命令运行:
py.test test_large_memory.py -s -v
最简单的解决方案是在self
中显式清除分配给tearDown
的任何大对象或需要清理的任何对象(例如数据库连接)。
<强>参考文献:强>
Python’s leaky TestCase
Issue 11798: Test cases not garbage collected after run - Python tracker
答案 1 :(得分:5)
您根本不必删除所有这些属性。
TestCase
实例最终会在tearDown
之后被丢弃;每个测试都使用新鲜,干净,有光泽且最重要的空新实例运行。实例上的任何属性都将被清除,一旦测试套件运行,引用计数就会丢失,如果实例是对这些值的唯一引用,它们将从内存中消失。
引用unittest.TestCase()
documentation:
class unittest.TestCase(methodName='runTest')
TestCase
类的实例代表unittest Universe中最小的可测试单元。 [...]。TestCase
的每个实例都将运行一个测试方法:名为 methodName 的方法。
强调我的;测试运行器将创建这些实例,传入要运行的测试方法的名称;如果您有方法test_foo
和test_bar
,则会创建传递这些名称的实例。
使用tearDown
清除外的测试实例;删除临时文件,删除模拟补丁,关闭数据库连接等。TestCase
实例只有在所有测试运行后才会最终确定(从内存中删除),因为测试运行器可能希望稍后访问每个测试在全套运行结束时提供有关它们的详细信息。
答案 2 :(得分:0)
我有teardown(self)
时总是跑setUp(self)
。这样可以防止由于累积过多的内存而导致“ kill 9”错误。通过将变量设置为None
,每次单元测试后都会清除总内存。
class TestExample(unittest.TestCase):
def setUp(self):
self.example_var = "some small or large amount of data"
def teardown(self):
self.example_var = None