Django SQLite 测试时尝试覆盖数据库
我在使用Django的测试工具时遇到了一个奇怪的问题,卡住了,所以想请教一下该怎么解决,或者至少该从哪里入手。
当我运行以下代码来测试我的teddybears应用时:
python manage.py test teddybears
我收到了这个错误:
...django/db/backends/sqlite3/base.py", line 344, in execute
return Database.Cursor.execute(self, query, params)
django.db.utils.DatabaseError: table "teddybears_teddybear" already exists
数据库不应该默认以“test”开头吗?这样可以避免名字冲突。我把数据库改成了“:memory:”来试图避免这个问题,但错误依然存在。
开发环境一切正常,功能也都按预期运行,只是测试工具无法工作。任何关于可能导致这个问题的原因或该查看哪里的信息都将非常感谢。
我在本地开发中使用SQLite,并且使用的是Django 1.4.3。
以下是完整的错误信息:
> python manage.py test teadybears
Creating test database for alias 'default'...
Traceback (most recent call last):
File "manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/core/management/__init__.py", line 443, in execute_from_command_line
utility.execute()
File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/core/management/__init__.py", line 382, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/core/management/commands/test.py", line 49, in run_from_argv
super(Command, self).run_from_argv(argv)
File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/core/management/base.py", line 196, in run_from_argv
self.execute(*args, **options.__dict__)
File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/core/management/base.py", line 232, in execute
output = self.handle(*args, **options)
File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/core/management/commands/test.py", line 72, in handle
failures = test_runner.run_tests(test_labels)
File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/test/simple.py", line 381, in run_tests
old_config = self.setup_databases()
File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/test/simple.py", line 317, in setup_databases
self.verbosity, autoclobber=not self.interactive)
File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/db/backends/creation.py", line 271, in create_test_db
load_initial_data=False)
File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/core/management/__init__.py", line 150, in call_command
return klass.execute(*args, **defaults)
File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/core/management/base.py", line 232, in execute
output = self.handle(*args, **options)
File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/core/management/base.py", line 371, in handle
return self.handle_noargs(**options)
File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/core/management/commands/syncdb.py", line 102, in handle_noargs
cursor.execute(statement)
File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/db/backends/sqlite3/base.py", line 344, in execute
return Database.Cursor.execute(self, query, params)
django.db.utils.DatabaseError: table "teadybears_teadybear" already exists
回复:
这是我的数据库设置:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
'NAME': 'database.sqlite', # Or path to database file if using sqlite3.
'USER': '', # Not used with sqlite3.
'PASSWORD': '', # Not used with sqlite3.
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
'PORT': '', # Set to empty string for default. Not used with sqlite3.
}
}
我之前确实有这个设置,但没有任何变化:
if 'test' in sys.argv:
DATABASES['default']['NAME'] = ':memory:'
真让人抓狂……
不幸的是,这个问题没有得到解决。我尝试了所有建议的办法,除了更改数据库名称,但这也没有解决问题。
我尝试了所有建议,包括:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
'NAME': 'database.sqlite', # Or path to database file if using sqlite3.
'USER': '', # Not used with sqlite3.
'PASSWORD': '', # Not used with sqlite3.
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
'PORT': '', # Set to empty string for default. Not used with sqlite3.
'TEST_NAME': 'mud',
}
}
现在它问我:
python manage.py test teddybears
Creating test database for alias 'default'...
Destroying old test database 'default'...
Type 'yes' if you would like to try deleting the test database 'mud', or 'no' to cancel:
还是出现同样的错误。
我真不想为了修复这个问题而把项目迁移到另一个干净的项目中,但这实在是让人烦恼。
我终于找到了问题所在。项目中的一个模型在Meta类上设置了一个值,导致测试失败。
class TeddybearExtra(Teddybear):
class Meta:
db_table = 'teddybears_teddybear'
正如你所看到的,它是原始模型的一个子类,由于“db_table”属性被明确设置,覆盖了自动生成的表名。在这里学到的教训是,在Meta对象上设置db_table属性会导致测试工具出现问题。只有在绝对需要这样处理时才这样做。
2 个回答
你是不是指向了正确的设置模块?试试这个:
python manage.py test teddybears --settings=myproject.settings.test
文档中有两个部分可能和你遇到的问题有关:
https://docs.djangoproject.com/en/dev/topics/testing/overview/#the-test-database
默认情况下,测试数据库的名字是通过在数据库名称前加上“test_”来生成的,这个名称是从DATABASES设置中的NAME值来的。当使用SQLite数据库引擎时,测试默认会使用一个内存数据库(也就是说,数据库会在内存中创建,完全不使用文件系统!)。如果你想用不同的数据库名称,可以在DATABASES中的字典里为任何数据库指定TEST_NAME。
还有……
如果你的测试需要访问数据库,比如创建或查询模型,确保你的测试类是从django.test.TestCase继承的,而不是unittest.TestCase。
在上面的例子中,我们实例化了一些模型,但没有把它们保存到数据库中。使用unittest.TestCase会避免每个测试都在一个事务中运行和刷新数据库的开销,但对于大多数应用来说,这样写的测试范围会比较有限,所以使用django.test.TestCase会更简单。
所以首先,确保你的测试是继承自django.test.TestCase
。其次,试着把TEST_NAME
设置为testdb.sqlite
,看看这样是否能解决你的问题。你可能还想指定数据库的路径,比如/Work/database.sqlite
,否则(我觉得)数据库会在你执行manage.py
的目录下创建,这可能并不是你想要的。
最后,确保你加载的是正确的settings
文件来进行测试。