Cer*_*rin 19 python database sqlite django unit-testing
我正在尝试使用Django 1.3进行单元测试.通常,我使用MySQL作为我的数据库后端,但由于单个单元测试的旋转速度非常慢,我使用的是Sqlite3.
所以,为了我的单元测试切换到Sqlite3,在我的settings.py中,我有:
import sys
if 'test' in sys.argv:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME':'/tmp/database.db',
'USER' : '',
'PASSWORD' : '',
'HOST' : '',
}
}
Run Code Online (Sandbox Code Playgroud)
当我运行我的unittest时python manage.py test myapp.Test.test_myfunc,我得到错误:
DatabaseError: no such table: django_content_type
Run Code Online (Sandbox Code Playgroud)
谷歌搜索显示有一个小的可能 原因,这种错误,其中没有一个似乎适用于我.我没有运行Apache,所以我没有看到权限如何成为一个问题.正在创建文件/tmp/database.db,因此/ tmp是可写的.应用程序django.contrib.contenttypes包含在我的INSTALLED_APPS中.
我错过了什么?
编辑:我在Django 1.5中再次遇到这个问题,但没有提出的解决方案.
Stv*_*vnW 12
在Django 1.4,1.5,1.6,1.7或1.8中,它应该足以使用:
if 'test' in sys.argv:
DATABASES['default']['ENGINE'] = 'django.db.backends.sqlite3'
Run Code Online (Sandbox Code Playgroud)
不必覆盖TEST_NAME1,也不必调用syncdb以运行测试.正如@osa指出的那样,SQLite引擎的默认设置是在memory(TEST_NAME=':memory:')中创建测试数据库.调用syncdb不应该是必要的,因为Django的测试框架将通过调用syncdb或migrate取决于Django版本自动执行此操作.2您可以观察到这一点manage.py test -v [2|3].
非常松散地说Django通过以下方式设置测试环境:
NAME从您的加载常规数据库settings.py__init__()称为)NAME为值TEST_NAMENAME这是一个问题:在第2步,NAME仍然指向您的常规(非测试)数据库.如果您的测试包含类级别查询或查询__init__(),则它们将针对常规数据库运行,这可能不是您所期望的.这在bug#21143中确定.
不要这样做:
class BadFooTests(TestCase):
Foo.objects.all().delete() # <-- class level queries, and
def __init__(self):
f = Foo.objects.create() # <-- queries in constructor
f.save() # will run against the production DB
def test_foo(self):
# assert stuff
Run Code Online (Sandbox Code Playgroud)
因为这些将针对指定的数据库运行NAME.如果NAME在此阶段指向有效的数据库(例如您的生产数据库),则查询将运行,但可能会产生意外后果.如果您已覆盖ENGINE和/或未NAME指向预先存在的数据库,则将抛出异常,因为尚未创建测试数据库:
django.db.utils.DatabaseError: no such table: yourapp_foo # Django 1.4
DatabaseError: no such table: yourapp_foo # Django 1.5
OperationalError: no such table: yourapp_foo # Django 1.6+
Run Code Online (Sandbox Code Playgroud)
相反:
class GoodFooTests(TestCase):
def setUp(self):
f = Foo.objects.create() # <-- will run against the test DB
f.save() #
def test_foo(self):
# assert stuff
Run Code Online (Sandbox Code Playgroud)
因此,如果您看到错误,请检查您的测试是否包含可能在测试类方法定义之外的数据库中的任何查询.
[1]在Django中> = 1.7,DATABASES[alias]['TEST_NAME']被弃用赞成
[2]见的方法在DATABASES[alias]['TEST']['NAME']create_test_db()db/backends/creation.py
尝试了上述所有方法后,我最终发现了可能发生这种情况的另一个原因:-
如果您的任何模型不是由您的迁移之一创建的。
我做了一些调试,似乎 Django 测试通过按顺序应用所有迁移来设置数据库,从001_initial.py开始,然后尝试从基于您的models.py的表中进行 SELECT
在我的情况下,一个表没有以某种方式添加到迁移中,而是手动添加的,因此无法正确应用完整的迁移集。当我手动修复001_initial.py迁移以创建此表时,OperationalError 消失了。
您的数据库可能是空的,它必须设置与您的模型对应的所有表。通常,这可以通过python manage.py syncdb首先运行来创建所有数据库表来完成。问题是,在你的情况下,当你运行syncdb时,python不会看到你正在运行测试,所以它会尝试在你的MySQL数据库中设置表。
要解决这个问题,请暂时更改
if 'test' in sys.argv:
Run Code Online (Sandbox Code Playgroud)
到
if True:
Run Code Online (Sandbox Code Playgroud)
然后运行python manage.py syncdb以设置 sqlite 数据库表。现在一切都已设置完毕,您可以重新安装if 'test'...,一切都应该顺利运行。但是,您可能希望将数据库移出该/tmp目录:每次运行测试时,django 都需要重新使用相同的数据库,否则您必须在每次测试之前创建数据库表。
请注意,如果添加新模型,则需要重复此过程以在 sqlite 中创建新表。如果向现有模型添加新字段,则需要使用 sqlite 接口和 手动向 sqlite 数据库添加列ALTER TABLE...,或者使用 South 等工具自动添加列。
| 归档时间: |
|
| 查看次数: |
9885 次 |
| 最近记录: |