使用Sqlite3运行Django Unittest时缺少表 [英] Missing Table When Running Django Unittest with Sqlite3

查看:287
本文介绍了使用Sqlite3运行Django Unittest时缺少表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图用Django 1.3运行一个单元测试。通常,我使用MySQL作为我的数据库后端,但是由于对单个单元测试来说,这是非常慢的,因此我使用Sqlite3。



所以要切换到Sqlite3对于我的单位测试,在我的settings.py我有:

  import sys 
如果在sys.argv中'test' :
DATABASES = {
'default':{
'ENGINE':'django.db.backends.sqlite3',
'NAME':'/ tmp / database.db ',
'USER':'',
'PASSWORD':'',
'HOST':'',
}
}

当我运行我的unittest与 python manage.py test myapp.Test.test_myfunc ,我得到错误:

  DatabaseError:没有这样的表:django_content_type 

Google搜索显示有一个几个可能这个 =https://stackoverflow.com/questions/4636970/sqlite3-operationalerror-unable-to-open-database-file>错误,这些都不适用于我。我没有运行Apache,所以我看不到权限是一个问题。正在创建/tmp/database.db文件,所以/ tmp是可写的。应用程式django.contrib.contenttypes包含在我的INSTALLED_APPS中。



我缺少什么?



编辑:我在Django 1.5中再次遇到这个问题,但是没有一个提出的解决方案可行。

解决方案

在Django 1.4,1.5,1.6 ,1.7或1.8它应该足以使用:

 如果在sys中为'test'。 argv:
DATABASES ['default'] ['ENGINE'] ='django.db.backends.sqlite3'

不需要覆盖 TEST_NAME 1 ,也不要调用 syncdb 为了运行测试。如@osa指出,SQLite引擎的默认值是在内存中创建测试数据库( TEST_NAME =':memory:')。调用 syncdb 不是必需的,因为Django的测试框架将通过调用 syncdb 迁移取决于Django版本。 2 可以用 manage.py test -v [2 | 3]

非常松散地Django通过以下方式设置测试环境:


  1. 从您的 settings.py
  2. 加载正常数据库 NAME
  3. 发现和构建您的测试类( __ init __()被调用)

  4. 设置数据库 NAME TEST_NAME

  5. 针对数据库运行测试 NAME

这是擦:在第2步, NAME 仍然指向您的常规(非测试)数据库。如果您的测试在 __ init __()中包含类级别的查询或查询,则它们将针对常规数据库运行,这可能不是您期望的。这在错误#21143 中已被识别。



不要do:

  class BadFooTests(TestCase):
Foo.objects.all()。delete()#< - 类级别查询和

def __init __(self):
f = Foo.objects.create()#< - 构造函数中的查询
f.save() #将针对生产DB运行

def test_foo(self):
#assert stuff

,因为这些将针对 NAME 中指定的数据库运行。如果 NAME 在此阶段指向一个有效的数据库(例如您的生产数据库),查询将运行,但可能会产生意想不到的后果。如果您已经覆盖 ENGINE 和/或 NAME ,使其不指向预先存在的数据库,则会出现异常将被抛出,因为测试数据库尚未创建:

  django.db.utils.DatabaseError:没有这样的表:yourapp_foo #Django 1.4 
DatabaseError:没有这样的表:yourapp_foo#Django 1.5
操作错误:没有这样的表:yourapp_foo#Django 1.6+

而不是:

  class GoodFooTests(TestCase):

def setUp(self):
f = Foo.objects.create()#< - 将针对测试DB运行
f.save()#

def test_foo(self):
#assert stuff

所以,如果你看到错误,看到您的测试不包括任何可能在测试类方法定义之外的数据库的查询。






[1]在Django> = 1.7, DATABASES [别名] ['TEST_NAME'] 已停用,赞成 DATABASES [alias] ['TEST'] ['NAME']

[2] code> create_test_db()方法在 db / backends / creation.py


I'm trying to run a unittest with Django 1.3. Normally, I use MySQL as my database backend, but since this is painfully slow to spinup for a single unittest, I'm using Sqlite3.

So to switch to Sqlite3 just for my unittests, in my settings.py I have:

import sys
if 'test' in sys.argv:
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME':'/tmp/database.db',
            'USER'       : '',
            'PASSWORD' : '',
            'HOST'     : '',
        }
    }

When I run my unittest with python manage.py test myapp.Test.test_myfunc, I get the error:

DatabaseError: no such table: django_content_type

Googling shows there are a few of possible reasons for this error, none of which seem applicable to me. I'm not running Apache, so I don't see how permissions would be an issue. The file /tmp/database.db is being created, so /tmp is writable. The app django.contrib.contenttypes is included in my INSTALLED_APPS.

What am I missing?

Edit: I ran into this problem again in Django 1.5, but none of the proposed solutions work.

解决方案

In Django 1.4, 1.5, 1.6, 1.7, or 1.8 it should be sufficient to use:

if 'test' in sys.argv:
    DATABASES['default']['ENGINE'] = 'django.db.backends.sqlite3'

It should not be necessary to override TEST_NAME1, nor to call syncdb in order to run tests. As @osa points out, the default with the SQLite engine is to create the test database in memory (TEST_NAME=':memory:'). Calling syncdb should not be necessary because Django's test framework will do this automatically via a call to syncdb or migrate depending on the Django version.2 You can observe this with manage.py test -v [2|3].

Very loosely speaking Django sets up the test environment by:

  1. Loading the regular database NAME from your settings.py
  2. Discovering and constructing your test classes (__init__() is called)
  3. Setting the database NAME to the value of TEST_NAME
  4. Running the tests against the database NAME

Here's the rub: At step 2, NAME is still pointing at your regular (non-test) database. If your tests contain class-level queries or queries in __init__(), they will be run against the regular database which is likely not what you are expecting. This is identified in bug #21143.

Don't do:

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

since these will be run against the database specified in NAME. If NAME at this stage points to a valid database (e.g. your production database), the query will run, but may have unintended consequences. If you have overridden ENGINE and/or NAME such that it does not point to a pre-existing database, an exception will be thrown because the test database has yet to be created:

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+

Instead do:

class GoodFooTests(TestCase):

    def setUp(self):
        f = Foo.objects.create()   # <-- will run against the test DB
        f.save()                   #

    def test_foo(self):
        # assert stuff

So, if you are seeing errors, check to see that your tests do not include any queries that might hit the database outside of your test class method definitions.


[1] In Django >= 1.7, DATABASES[alias]['TEST_NAME'] is deprecated in favour of DATABASES[alias]['TEST']['NAME']
[2] See the create_test_db() method in db/backends/creation.py

这篇关于使用Sqlite3运行Django Unittest时缺少表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆