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

时间:2010-06-22 18:45:21

标签: python mysql django unit-testing

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

因为我知道测试数据库总是很小,为什么我不能只是将系统配置为始终将整个测试数据库保存在RAM中?切勿触摸磁盘。如何在Django中配置它?我更喜欢继续使用MySQL,因为这是我在制作中使用的内容,但是如果SQLite 3或其他东西让我很容易,我就会这样做。

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

8 个答案:

答案 0 :(得分:155)

如果在运行测试时将数据库引擎设置为sqlite3,Django will use a in-memory database

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

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

或者在Django 1.2中:

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

最后在Django 1.3和1.4中:

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

(对于Django 1.3,后端的完整路径并非绝对必要,但会使设置向前兼容。)

如果您遇到南迁移问题,还可以添加以下行:

    SOUTH_TESTS_MIGRATE = False

答案 1 :(得分:80)

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

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
    

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

答案 2 :(得分:22)

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,则无法使用此功能。

答案 3 :(得分:15)

我无法回答你的主要问题,但你可以采取一些措施来加快速度。

首先,确保您的MySQL数据库设置为使用InnoDB。然后它可以使用事务在每次测试之前回滚数据库的状态,这在我的经验中导致了大规模的加速。您可以在settings.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" } 
        }
    }

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

答案 4 :(得分:10)

你可以做双重调整:

  • 使用事务表:在每个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

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

答案 5 :(得分:3)

另一种方法:在使用RAM磁盘的tempfs中运行另一个MySQL实例。本博文中的说明: Speeding up MySQL for testing in Django

优点:

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

答案 6 :(得分:2)

扩展Anurag的答案我通过创建相同的test_settings并将以下内容添加到manage.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只能通过命令行使用,所以不需要混乱设置

答案 7 :(得分:0)

在下面的setting.py

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