你如何阻止Django单元测试运行南迁移?
我有一个自定义的Django应用程序myapp,我尝试使用manage.py test myapp
进行测试但是当我运行它时出现错误:
django.db.utils.OperationalError: table "myapp_mymodel" already exists
果然,追溯显示南方正在被执行:
File "/usr/local/myproject/.env/local/lib/python2.7/site-packages/south/management/commands/test.py", line 8, in handle
super(Command, self).handle(*args, **kwargs)
但是,在我的设置中,我已指定:
SOUTH_TESTS_MIGRATE = 0
SKIP_SOUTH_TESTS = 1
我认为应该阻止Django的测试框架执行任何南方组件。
我做错了什么?
编辑:我只是通过以下方式解决了这个问题:
if 'test' in sys.argv:
INSTALLED_APPS.remove('south')
然而,我得到了:
ImproperlyConfigured: settings.DATABASES is improperly configured. Please supply the NAME value.
对于我的测试数据库设置,我使用的是:
DATABASES = {
'default':{
'ENGINE': 'django.db.backends.sqlite3'
}
}
在Django 1.4中运行良好。现在我使用Django 1.5,我猜这不是犹太人。但是,没有NAME值,我认为它可以修复它。他们都报告我的桌子都没有。我试过了:
DATABASES = {
'default':{
'ENGINE': 'django.db.backends.sqlite3',
'NAME': '/dev/shm/test.db',
'TEST_NAME': '/dev/shm/test.db',
}
}
DATABASES = {
'default':{
'ENGINE': 'django.db.backends.sqlite3',
'NAME': ':memory:',
'TEST_NAME': ':memory:',
}
}
DATABASES = {
'default':{
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(os.path.dirname(__file__), 'test.db'),
'TEST_NAME': os.path.join(os.path.dirname(__file__), 'test.db'),
}
}
每个似乎都创建了一个物理test.db文件,我不明白,因为单元测试应该在内存中运行。它永远不应该保存到磁盘上。据推测,它在创建文件之后但在执行实际单元测试之前未能运行syncdb。我该如何解决这个问题?
编辑:我发现,在我的一个表单中,我通过直接查询模型来填充字段选择(而我应该在表单内部 init 中执行此操作),因此,当Django的测试框架导入我的模型时,它试图在创建sqlite3数据库之前读取该表。我解决了这个问题,但现在我收到了错误:
DatabaseError: table "myapp_mythroughmodel" already exists
所以我回到原点,即使它抛出的异常类型与最初不同。
编辑:我通过模型定义了重复,导致Django尝试创建它两次,导致错误。
答案 0 :(得分:3)
这也发生在遗留代码上,但出于另一个原因。
我有两个模型,db_table引用相同的db表。 我知道那是愚蠢的,但这不是我的错)
我从来没有在互联网上找到任何可以帮助我的东西。 我被详细设置为3(manage.py test -v 3)保存 希望这对任何人都有帮助。
class Bla1(Model):
some_column = ...
class Meta:
db_table = 'some_table'
class Bla2(Model):
some_column = ...
class Meta:
db_table = 'some_table'
答案 1 :(得分:2)
此错误是几个问题的结果。我会在这里总结他们,以帮助那些可能偶然发现这一点的人。
确保您的settings.DATABASES设置正确。 Django的文档提到使用TEST_NAME
,但为了清楚起见,我发现检查test
命令并覆盖所有内容更容易。例如在我的settings.py的底部,我有:
if 'test' in sys.argv:
DATABASES = {
'default':{
'ENGINE': 'django.db.backends.sqlite3',
'NAME': ':memory:',
},
}
除非你有充分的理由,总是使用:memory:
来确保它在内存中运行,并且不会创建一个会陷入磁盘的物理文件。由于一些奇怪的原因,SO上的许多其他答案建议指定test.db文件的文字路径进行测试。这是一个可怕的建议。
除非你想测试South和/或你的South迁移,否则禁用South,因为它只会使事情变得复杂:
SOUTH_TESTS_MIGRATE = False
SKIP_SOUTH_TESTS = True
不要像我一样愚蠢,并尝试在模型创建之前访问它们。这主要意味着不直接参考其他模型或表格领域的模型。 e.g。
class MyForm(forms.Form):
somefield = forms.ChoiceField(
required=True,
choices=[(_.id, _.name) for _ in OtherModel.objects.filter(criteria=blah)],
)
这可能适用于数据库已经存在的代码,但是当它尝试加载测试时会破坏Django的unittest框架,这会加载你的models.py和forms.py,导致它读取一个没有的表。存在。相反,请在表单__init__()
。