如何只在内存中运行 Django 的测试数据库?

我的 Django 单元测试需要很长时间才能运行,因此我正在寻找加快运行速度的方法。我正在考虑安装一个 额外印花税,但我知道这也有它的缺点。当然,我可以用我的代码做一些事情,但是我正在寻找一个结构性的修复。即使运行单个测试也很慢,因为每次都需要重新构建/向南迁移数据库。所以我的想法是..。

既然我知道测试数据库总是很小,为什么我不能只配置系统来保持整个测试数据库在 RAM 中?永远不要碰那个磁盘。我如何在 Django 中配置它?我更愿意继续使用 MySQL,因为这是我在生产中使用的,但如果 SQLite3或其他东西使这很容易,我会走那条路。

SQLite 或 MySQL 是否有完全在内存中运行的选项?应该可以配置一个 RAM 磁盘,然后配置测试数据库在那里存储它的数据,但我不知道如何告诉 Django/MySQL 为某个数据库使用不同的数据目录,尤其是因为每次运行都会被擦除并重新创建。(我用的是 Mac FWIW。)

53565 次浏览

MySQL 支持一个名为“ MEMORY”的存储引擎,您可以在数据库配置(settings.py)中配置该引擎:

    'USER': 'root',                      # Not used with sqlite3.
'PASSWORD': '',                  # Not used with sqlite3.
'OPTIONS': {
"init_command": "SET storage_engine=MEMORY",
}

请注意,MEMORY 存储引擎不支持 blob/text 列,所以如果您使用 django.db.models.TextField,那么这个引擎不会为您工作。

我不能回答你的主要问题,但是你可以做一些事情来加快进度。

首先,确保将 MySQL 数据库设置为使用 InnoDB。然后它可以在每次测试之前使用事务来回滚数据库的状态,根据我的经验,这样可以大大提高速度。您可以在 setings.py (Django 1.2语法)中传递数据库 init 命令:

DATABASES = {
'default': {
'ENGINE':'django.db.backends.mysql',
'HOST':'localhost',
'NAME':'mydb',
'USER':'whoever',
'PASSWORD':'whatever',
'OPTIONS':{"init_command": "SET storage_engine=INNODB" }
}
}

其次,您不需要每次都运行南部迁移。在 setings.py 中设置 SOUTH_TESTS_MIGRATE = False,数据库将使用普通 syncdb 创建,这比运行所有历史迁移要快得多。

如果在运行测试时将数据库引擎设置为 sqlite3,则 姜戈会用内存数据库

在我的 settings.py中,我使用这样的代码在运行测试时将引擎设置为 sqlite:

if 'test' in sys.argv:
DATABASE_ENGINE = 'sqlite3'

或者在姜戈1.2中:

if 'test' in sys.argv:
DATABASES['default'] = {'ENGINE': 'sqlite3'}

最后是姜戈1.3和1.4:

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

(对于 Django 1.3来说,后端的完整路径并不是必需的,但是可以使设置向前兼容。)

如果您在南方移民方面遇到问题,还可以添加以下一行:

    SOUTH_TESTS_MIGRATE = False

你可以做双重调整:

  • 使用事务性表: 在每个 TestCase 之后,使用数据库回滚设置初始 fixture 状态。
  • 将您的数据库数据目录放在 ramdisk 上: 就创建数据库而言,您将获得更多,并且运行测试将更快。

我使用这两种技巧,我很高兴。

如何在 Ubuntu 上设置 MySQL:

$ sudo service mysql stop
$ sudo cp -pRL /var/lib/mysql /dev/shm/mysql


$ vim /etc/mysql/my.cnf
# datadir = /dev/shm/mysql
$ sudo service mysql start

注意,它只是用于测试,在从内存重新启动数据库之后将丢失数据库!

我通常为测试创建一个单独的设置文件,并在 test 命令中使用它,例如。

python manage.py test --settings=mysite.test_settings myapp

它有两个好处:

  1. 在 sys.argv 中,您不必检查 test或任何这样的神奇单词,test_settings.py可以简单地

    from settings import *
    
    
    # make tests faster
    SOUTH_TESTS_MIGRATE = False
    DATABASES['default'] = {'ENGINE': 'django.db.backends.sqlite3'}
    

    或者您可以根据需要进一步调整它,将测试设置与生产设置干净地分离开来。

  2. 另一个好处是,您可以使用生产数据库引擎而不是 sqlite3运行测试,以避免细微的错误,因此在开发使用时

    python manage.py test --settings=mysite.test_settings myapp
    

    在提交代码之前运行一次

    python manage.py test myapp
    

    只是为了确保所有的测试都真正通过。

在 Anurag 的回答的基础上,我简化了这个过程,创建了相同的 test _ sets,并将以下内容添加到 manager. py

if len(sys.argv) > 1 and sys.argv[1] == "test":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.test_settings")
else:
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")

似乎更干净,因为 sys 已经被导入,而 manage.py 只能通过命令行使用,所以不需要把设置弄得乱七八糟

另一种方法是: 让另一个 MySQL 实例运行在一个使用 RAM 磁盘的 temfs 中。这篇博文的说明: 加速 MySQL 在 Django 中的测试

优点:

  • 您使用的数据库与生产服务器使用的数据库完全相同
  • 不需要更改默认的 mysql 配置

使用下面的 setting.py

DATABASES['default']['ENGINE'] = 'django.db.backends.sqlite3'