【问题标题】:Django Testing: no data in temporary database fileDjango 测试:临时数据库文件中没有数据
【发布时间】:2012-03-07 19:07:24
【问题描述】:

我正在使用settings.py中设置如下的sqlite3数据库:

DATABASES = {
    'default': {
        'ENGINE': 'django.contrib.gis.db.backends.spatialite',
        'NAME': 'path/to/config.sqlite',
        'TEST_NAME': 'path/to/test-config.sqlite',
        # ... USER, PASSWORD and PORT left out for brevity
    }
}

在测试运行期间开始于:

python manage.py test myapp.mytest

这会临时创建一个数据库文件path/to/test-config.sqlite,我需要在另一个加载了所需装置的应用程序中使用它。

然而,数据库文件是空的,我在一次测试的暂停期间断言:

sqlite> select * from someapp_somemodel;

... no results here :(

其他不需要sqlite文件且内存数据库足够的测试用例,不会出现错误。

我的问题:

  • 如果 django 无论如何创建它,为什么不将其数据刷新到数据库文件?和
  • 我如何说服 django 这样做,因为我需要将数据转储到临时数据库文件中?

编辑

如果有任何兴趣,我正在使用 Django 1.3.1。

EDIT2

我对fixtures很熟悉,我使用它们来填充数据库,但我的问题是fixtures的数据在测试期间没有写入数据库文件。抱歉,如果我对这个事实不够清楚。

EDIT3

由于我的问题需要澄清,请考虑以下测试设置(与我实际所做的接近):

class SomeTestCase(django.test.TestCase):
    fixtures = ["some_fixture.json", "some_other_fixture.json"]

    def testSomething(self):
        import pdb; pdb.set_trace()

testSomething 方法运行到断点时,我启动sqlite3 程序并连接到由Django 创建的临时数据库文件。固定装置已加载(我知道,因为其他测试也可以正常工作),但数据未写入临时数据库文件。

【问题讨论】:

  • “我在一个测试暂停期间断言”哪个测试断言? Django 测试或您的应用程序加载数据库?你能澄清一下吗?
  • Django 不会将数据从“正常”数据库转储到测试数据库,因为这没有任何意义。如果测试使用数据库,他们可能会期望数据库处于最小和固定状态。现在这个“我使用它们 [fixtures] 来填充数据库,但我的问题是在测试期间来自fixtures 的数据没有写入数据库文件。” 完全不清楚。不应该在 运行测试之前加载固定装置吗?你的意思是你必须手动加载灯具吗?您能否详细说明并提供示例(如果可能,可运行代码)。
  • 只是出于好奇:您正在测试什么行为实际上需要一个 sqlite db 文件?您打算使用 sqlite 上线吗?
  • @jpic: 没有人在这里谈论 normal 数据库,我的问题只是在测试期间创建的临时数据库中,并填充了从指定夹具中获取的数据.是的,固定装置在每次测试之前加载,但显然它们没有写入文件。我已经用一个测试用例更新了我的答案,显示了我想要做什么。
  • @jpic:数据库文件创建于test-config.sqlite,是一个包含我所有需要的表的有效sqlite 文件。唯一缺少的是表格内容。一旦最后一个测试用例完成,这个文件就会被删除。

标签: python django sqlite django-testing django-database


【解决方案1】:

我找到了一种方法,但由于我也弄乱了 hdparm(使用 -F 或 -W 0/1),我不知道它是否适合你。我确实重新启动并重新尝试以确保思想。此外,此测试没有有 SpatiaLite,但正如您所说,这可能无关紧要。

无论如何,我们需要 2 个屏幕来重现这一点,screen0 运行测试,而 screen1 是一个 sh shell 与将 screen0 的进程暂停工作。

开始测试(screen0):

>>> ./manage.py test testapp
Creating test database for alias 'default'...
Destroying old test database 'default'...
Type 'yes' if you would like to try deleting the test database 'db_test.sqlite', or 'no' to cancel: yes
--Return--
None
> /home/jpic/testproject/testapp/tests.py(16)testSomething()
     14 
     15     def testSomething(self):
---> 16         import ipdb; ipdb.set_trace()

检查创建的测试数据库文件的大小,(screen1):

<<< 18:00.39 Mon Feb 20 2012!~/testproject 
<<< jpic@germaine!10004 env
>>> ls -l db_test.sqlite
-rw-r--r-- 1 jpic jpic 49152 2012-02-20 18:00 db_test.sqlite

从 python 运行 PRAGMA SYNCHRONOUS sql 命令(screen0):

ipdb> from django.db import connection; cursor = connection.cursor()
ipdb> cursor.execute("PRAGMA SYNCHRONOUS")
<django.db.backends.sqlite3.base.SQLiteCursorWrapper object at 0x294f348>
ipdb> 

检查数据库文件大小是否增加(screen1):

<<< 18:00.42 Mon Feb 20 2012!~/testproject 
<<< jpic@germaine!10005 env
>>> ls -l db_test.sqlite
-rw-r--r-- 1 jpic jpic 272384 2012-02-20 18:00 db_test.sqlite

数据已写入文件。

这对我来说没有多大意义,因为显然 PRAGMA SYNCHRONOUS 一个人should just query for the value(在我的情况下:2/FULL)。但在实践中,它会写入磁盘。请注意,如果您没有 2 (FULL),则应将其设置为 2:PRAGMA SYNCHRONOUS 2

现在,我不能说 what 是写的(它是完全写的吗?)因为我无法获得测试数据库:如果我在 screen1 中运行 sqlite db_test.sqlite 来获取测试数据库上的客户端:我不能运行任何命令(也不能选择,也不能 .dump),因为“SQL 错误:数据库已锁定”。但是,我想这就是你现在的问题了 B)

【讨论】:

  • 我很惊讶,这就像一个魅力!在我的盒子上(也许这也是因为spatialite 而不是sqlite)我从数据库读取没有任何问题。非常感谢!
【解决方案2】:

您似乎正在根据您的数据库引擎 'django.contrib.gis.db.backends.spatialite' 使用 GeoDjango 做一些事情。 GeoDjango 需要额外的设置,所以我猜它也需要一些额外的测试。 (如果您不使用 GeoDjango,只需使用 'django.db.backends.sqlite3' 作为数据库引擎。请保留 TEST_NAME,否则 Django 将在内存中创建测试数据库。)

加载空间数据有一个完整的过程,GeoDjango的安装文档非常详尽。这是直接创建SpatiaLite database 的链接。您需要对测试执行基本相同的操作。

来自testing docs

您需要下载 SpatiaLite 的初始化 SQL 脚本:

$wget http://www.gaia-gis.it/spatialite/init_spatialite-2.3.zip

$unzip init_spatialite-2.3.zip

如果 init_spatialite-2.3.sql 与您项目的 manage.py 位于同一路径,那么您所要做的就是: $ python manage.py test

【讨论】:

  • JCotton:你说得对,我正在使用 GeoDjango 和空间数据库。我目前正在使用settings.py 中的SPATIALITE_SQL 选项来引用init_spatialite-2.3.sql。没有它,测试过程会在设置数据库时引发异常。恐怕,使用spatialite 不是这里的核心问题,但无论如何谢谢。
【解决方案3】:

来自django documentation

...当使用 SQLite 数据库引擎时,测试将默认使用 内存数据库(即,数据库将在内存中创建, 完全绕过文件系统!)。如果你想使用不同的 数据库名称,在字典中为任何给定的指定 TEST_NAME DATABASES中的数据库。

另外,如果你read about fixture loading:

...在每个测试用例开始时,在setUp() 运行之前,Django 会刷新数据库,将数据库返回到调用syncdb 后直接所处的状态...

如果您需要一个加载了一些固定装置的新数据库,您当然可以通过创建一个运行 syncdb 的空数据库并使用 django-admin.py loaddata 加载一些固定装置来实现!

【讨论】:

  • lazerscience:我知道 django 测试是如何在 setUp 方法之前加载固定装置的。我的问题是我需要将测试用例的所有数据写入我从其他应用程序打开的 same sqlite 数据库文件。我真的不想依赖第二个预填充的数据库。
【解决方案4】:

也许和how Django tests use transactions有关?

如果您在 settings.py 中turn off all transactions,请检查问题是否仍然存在:

DISABLE_TRANSACTION_MANAGEMENT = True

【讨论】:

  • 这是一个不错的 hack,不幸的是它没有解决问题。数据库文件还是空的。
【解决方案5】:

您是否已运行初始同步数据库来创建数据库表? (python yourproject/manage.py syncdb)

在你的settings.py中,你在INSTALLED_APPS下安装了哪些应用?

在您的项目中,您构建了哪些模型?

根据您在 INSTALLED_APPS 中安装的应用程序以及您添加到项目中的自定义模型,将决定 syncdb 将创建哪些数据库。

【讨论】:

  • Adam:syncdb 命令只影响 live*/*normal 数据库,而不是用于测试 python manage.py test ... 的数据库。该命令在我的项目中经常使用,但不能解决所描述的问题。
猜你喜欢
  • 2020-11-17
  • 2013-09-25
  • 2011-08-20
  • 2013-08-05
  • 1970-01-01
  • 2015-12-06
  • 1970-01-01
  • 2020-12-30
  • 2012-04-20
相关资源
最近更新 更多