Django单元测试中对象ID递增的问题
我在 Debian squeeze 上使用 Django 1.2.3-3+squeeze1 和 PostgreSQL 8.4.7-0squeeze2(不过我觉得 PostgreSQL 在这里并不重要),并且在运行基于 unittest 的 Django 单元测试,使用了以下的 setUp 和 tearDown 方法。
def setUp(self):
print "running setup"
self.c = Client()
self.user = User.objects.create_user('faheem', 'faheem@email.unc.edu', 'foo')
self.logged_in = self.c.login(username='faheem', password='foo')
settings.MEDIA_ROOT='/tmp/'
#settings.ZIP_UPLOAD='/var/tmp/zip/'
def tearDown(self):
print "running teardown"
FolderUpload.objects.all().delete()
FileUpload.objects.all().delete()
ZipFileUpload.objects.all().delete()
OldFileUpload.objects.all().delete()
# FIXME: Quick & dirty fix for the time being. Should make this a delete method.
os.system("rm -rf "+ settings.ZIP_UPLOAD + "/*")
我的想法是,在运行单元测试之间,数据库中的所有内容都应该被清除。根据 unittest 的文档,tearDown
就是用来做这个的。问题是,我发现不同的单元测试之间似乎还有一些状态被保留。具体来说,我看到 id 是递增的。比如说,如果我在 test1
中创建一个 ZipFileUpload
对象,然后在 test2
中再创建一个 ZipFileUpload
对象,我本来希望这两个对象的 id 都是 1
,但实际上我看到的是 test1
的 id 是 1
,而 test2
的 id 是 2
。如果这些 id 是来自某个在这些表之外的索引,那就说得通了。我对 Django 是怎么处理这个的了解不够,所以不确定是否真是这样。如果真是这样,我也不知道为什么会这样。对此如果能有些解释就太好了。
不管怎样,我希望能找到一种干净的方法来删除数据库,如果有人能推荐一个方法就好了。这个方法应该放在 tearDown
中。测试 Django 应用程序 提到了一下这个函数,但我没能从 django.test.utils
中导入它。令人困惑的是,这个函数似乎在 django/db/backends/creation.py
中。
destroy_test_db(old_database_name, verbosity=1)
销毁数据库,数据库的名称存储在 DATABASES 中的 NAME,并将 NAME 设置为使用提供的名称。
这句话的前半部分是可以理解的 - “销毁数据库,数据库的名称存储在 DATABASES 中的 NAME”,但“将 NAME 设置为使用提供的名称”是什么意思呢?我假设提供的名称是 old_database_name
。
在这个上下文中,NAME
是什么并不清楚。它是 DATABASES
中的 NAME
吗?如果是的话,为什么我还需要设置一个已经设置好的东西?我假设提供的名称是 old_database_name
,但如果是这样,为什么我还要把它设置为一个叫 old_database_name
的参数呢?这句话在开发文档中没有改变。
编辑:
在收到 Steve Mayne 的回复后(见下文),我想稍微详细说明一下背景。
这个应用程序最初是在 2007/2008/2009 年间编写的,包括单元测试。在那段时间里,我使用的是 Django 1.0 之前的版本。根据 Ken Cochran 的 Django 发布历史,1.0 版本是在 2008 年 9 月 3 日发布的。描述的设置在那段时间内运行得很好。我看到上面的 tearDown 函数最初是在 2007 年 12 月写的。所以,也许 Django 的行为发生了变化?
事后看来,我意识到像上面 tearDown
所做的那样清空表,并不能保证 id 计数会重置为 1
,因为序列可能是与表分开的一个对象。
感谢 Steve 提供的解决方案。如果有的话,我想听听关于序列重置的可移植解决方案。我也想了解如何让上面的 destroy_test_db
函数工作。
1 个回答
你可以用下面的SQL语句来重置每个表的ID序列:
SELECT pg_catalog.setval(pg_get_serial_sequence('table_name', 'id'), 1);
不过,只有在你的表是空的时候才应该这样做。