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

Leo*_*opd 118 python mysql django unit-testing

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

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

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

Eti*_*nne 157

如果在运行测试时将数据库引擎设置为sqlite3,Django将使用内存数据库.

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

if 'test' in sys.argv:
    DATABASE_ENGINE = 'sqlite3'
Run Code Online (Sandbox Code Playgroud)

或者在Django 1.2中:

if 'test' in sys.argv:
    DATABASES['default'] = {'ENGINE': 'sqlite3'}
Run Code Online (Sandbox Code Playgroud)

最后在Django 1.3和1.4中:

if 'test' in sys.argv:
    DATABASES['default'] = {'ENGINE': 'django.db.backends.sqlite3'}
Run Code Online (Sandbox Code Playgroud)

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

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

    SOUTH_TESTS_MIGRATE = False
Run Code Online (Sandbox Code Playgroud)

  • 在sys.argv`中注意这个"test"; 当你不想要它时它可能触发,例如`manage.py collectstatic -i test`.`sys.argv [1] =="test"`是一个更精确的条件,不应该有这个问题. (12认同)
  • 对,就是这样.我应该把它放在我的答案中!将它与SOUTH_TESTS_MIGRATE = False相结合,您的测试应该快得多. (9认同)
  • 这太棒了.在更新的django设置上使用这一行:'ENGINE':'sqlite3'如果在sys.argv中'test',那么'django.db.backends.mysql', (7认同)
  • @Tomasz Zielinski - 嗯,这取决于你在测试什么.但我完全同意,在最后和不时,您需要使用您的真实数据库(Postgres,MySQL,Oracle ......)运行测试.但是使用sqlite在内存中运行测试可以节省大量时间. (3认同)
  • 我将-1反转为+1:正如我现在看到的那样,使用sqlite进行快速运行并切换到MySQL进行例如最终的每日测试要快得多.(请注意,我必须进行虚拟编辑才能解锁投票) (3认同)
  • Django不应该与数据库无关吗?**应该*与每个数据库的功能几乎相同,对吧? (2认同)
  • 如果我是对的,如果您在设置中指定了 TEST_NAME,SQLite 将使用平面文件。对于你的第一个问题,你写过吗,它的功能应该几乎相同,但不一定功能完全相同。这就是为什么在将代码推送到生产之前,您确实需要在生产中使用的数据库引擎上运行测试至少一次。 (2认同)
  • @Etienne:啊,你是对的.当运行Django(`runserver`)时,Django将使sqlite使用平面文件DB但是在运行测试时没有`TEST_NAME`它将使用内存数据库(而不是平面文件,正如我所假设的).感谢您指出了这一点.您可能希望在答案中添加注释(将"TEST_NAME"保留为"无"或指定为":memory:"会导致内存数据库,其他任何内容都会导致平面文件数据库).否则,有人可能会使用sqlite引擎,但设置了"TEST_NAME",并想知道为什么要使用平面文件. (2认同)
  • 这似乎不适用于Django> = 1.5.它现在抱怨NAME字段丢失. (2认同)

Anu*_*yal 81

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

python manage.py test --settings=mysite.test_settings myapp
Run Code Online (Sandbox Code Playgroud)

它有两个好处:

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

    from settings import *
    
    # make tests faster
    SOUTH_TESTS_MIGRATE = False
    DATABASES['default'] = {'ENGINE': 'django.db.backends.sqlite3'}
    
    Run Code Online (Sandbox Code Playgroud)

    或者您可以根据需要进一步调整它,将测试设置与生产设置完全分开.

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

    python manage.py test --settings=mysite.test_settings myapp
    
    Run Code Online (Sandbox Code Playgroud)

    并且在提交代码之前运行一次

    python manage.py test myapp
    
    Run Code Online (Sandbox Code Playgroud)

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

  • 我喜欢这种方法.我有一堆不同的设置文件,并将它们用于不同的服务器环境,但我没有想过使用这种方法来选择不同的测试数据库.谢谢你的想法. (2认同)
  • @DylanYoung你可以通过将主要设置包含到test_settings中来干掉它,然后覆盖你想要测试的东西. (2认同)

muu*_*ope 22

MySQL支持名为"MEMORY"的存储引擎,您可以在数据库config(settings.py)中配置它:

    'USER': 'root',                      # Not used with sqlite3.
    'PASSWORD': '',                  # Not used with sqlite3.
    'OPTIONS': {
        "init_command": "SET storage_engine=MEMORY",
    }
Run Code Online (Sandbox Code Playgroud)

请注意,MEMORY存储引擎不支持blob/text列,因此如果您使用django.db.models.TextField此列将不适合您.

  • +1表示缺少对blob/text列的支持.它似乎也不支持交易(http://dev.mysql.com/doc/refman/5.6/en/memory-storage-engine.html). (5认同)

Dan*_*man 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" } 
        }
    }
Run Code Online (Sandbox Code Playgroud)

其次,您不需要每次都运行South迁移.设置SOUTH_TESTS_MIGRATE = False在你的settings.py和数据库将与普通的执行syncdb,这将是比通过所有历史悠久的迁移运行更快创建.


Pot*_*hur 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
Run Code Online (Sandbox Code Playgroud)

当心,它只是用于测试,重启后你的数据库从内存中丢失了!