在内存中运行 Django MySQL 测试

Posted

技术标签:

【中文标题】在内存中运行 Django MySQL 测试【英文标题】:Running Django MySQL tests in memory 【发布时间】:2013-02-20 11:54:31 【问题描述】:

我有一个使用 mysql 作为后端的 django 1.4 项目。我有要在内存中运行的测试设置

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

问题是我需要使用 mysql 功能(全文索引)。

有没有办法让 django 在内存中运行 MySQL 进行测试?

我的项目依赖全文索引。当我在syncdb上开发项目时,然后使用sql执行.sql文件以创建全文索引。

我想在我测试的函数中使用 django orm 全文搜索。我正在尝试在每个测试的初始化中手动添加全文索引,例如:

cursor.execute('alter table mytable add fulltext(one, two)')

这在使用 sqlite 时不起作用(我相信是因为 sqlite 不支持全文索引)

当我删除内存测试时,上面的 sql 确实有效。我喜欢内存测试的速度。 有没有办法在内存中运行 mysql?

人们如何测试依赖于数据库特定功能的应用?比如全文索引或gis等...他们必须在文件系统上正常运行测试吗?

谢谢

【问题讨论】:

mysql 是否支持表空间?在 linux 上,您可以将 dbs 表空间设置为放在 RAM 磁盘上。 cyberciti.biz/faq/howto-create-linux-ram-disk-filesystem 【参考方案1】:

MySQL 有一个MEMORY 存储引擎。您可以使用OPTIONS 键激活它:

if 'test' in sys.argv:
    DATABASES = 
        'default': 
            'ENGINE': 'django.db.backends.mysql',
            'HOST': 'localhost',
            'NAME': 'foo',
            'USER': 'bar',
            'PASSWORD': 'baz',
            'OPTIONS': 
                'init_command': 'SET storage_engine=MEMORY'
            
        
    

但是根据documentation:

MEMORY tables cannot contain BLOB or TEXT columns.

因此,我认为它对您(和许多其他)用例毫无用处。

我在this thread 中发现了一些加快 MySQL 测试速度的其他技巧。请务必阅读 Daniel Roseman 关于使用 INNODB 引擎的回答。

【讨论】:

【参考方案2】:

不要测试 MySQL。 MySQL 已经过其开发人员的测试。 您的工作是以这种方式编写代码,以便您可以用一个模拟 Python 对象替换 MySQL 连接,该对象将返回 MySQL 将返回的任何内容(或断言发送到 MySQL 的查询是否是您想要的)

【讨论】:

这里唯一的问题是,可能有多种访问数据库的方法 - 并且全部模拟它们会花费大量时间,而模拟太少会限制实施。理想情况下,测试应该是关于意图而不是实现。 这可能是一个很好的建议……在编写“hello, world”风格的程序时。任何与数据库对话的重要内容都取决于该数据库的行为,因此必须测试整个事物 - 否则您很快就会发现有问题的 db 所做的事情与您的 mock 不完全相同。跨度> @ayanami:在不同的存储引擎上进行测试,而不是在生产中使用的存储引擎也是如此。 MySQL 的 MEMORY 引擎在某些情况下的行为与 MyISAM 和 InnoDB 不同。一旦我们谈论集成测试(我们似乎在这种情况下),它们应该在目标配置上运行。这意味着这些测试有时会很慢。【参考方案3】:

正如monkut 在问题评论中建议的那样,您可以通过将测试数据库存储在RAM 驱动器上来获得一些MySql 加速。例如,如果在 Linux 上运行,则为 tmpfs 文件系统。但是,如果您担心测试期间的速度,这可能不会带来太大的速度提升,因为 MySql 通常会将其数据缓存在内存中。

我使用的方法是编写一个测试装饰器,它将跳过给定数据库后端不支持的测试,然后使用不同的settings.py 文件针对不同的后端进行测试。

在这里,我使用了django-nose 功能来帮助编写装饰器,以在任何测试数据库使用 SQLite 时跳过测试。

from nose import SkipTest
from django.conf import settings

def skip_if_sqlite(test_fn):
    """Nose test decorator to skip test if testing using sqlite databases.

    This may be useful when we know that a test will fail when using sqlite,
    possibly because the test uses functionality not supported on sqlite such
    as database views or full text indexes.

    This decorator can be used as follows:
    @skip_if_sqlite
    def my_test_that_shouldnt_run_if_sqlite_database(self):
        pass
    """

    @functools.wraps(test_fn)
    def wrapper(*args, **kwargs):
        # Skip test if any database contain a sqlite engine.
        for alias, db_settings in settings.DATABASES.iteritems():
            if 'sqlite' in db_settings['ENGINE']:
                raise SkipTest()
            return test_fn(*args, **kwargs)

    return wrapper

然后,使用不同的DATABASE 设置设置settings.test.mysqlsettings.test.sqlite。如果您使用 settings.test.sqlite 执行测试,则依赖于 MySql 特定功能的测试将被跳过,但如果您针对 settings.test.mysql 运行测试,则将执行测试。

这种方法允许您专门针对特定数据库后端的测试,但仍然可以灵活地在开发过程中针对更快的 SQLite 数据库运行大部分测试。

【讨论】:

以上是关于在内存中运行 Django MySQL 测试的主要内容,如果未能解决你的问题,请参考以下文章

Apache/MySQL 上的 Django 内存泄漏

创建测试数据库时出错 - django、docker、mysql

Mavericks 上的 Django 和 mysql 问题

如何使用 django 保持 tensorflow 会话在内存中运行

在 docker 中使用 selenium 运行 django 测试

在PyCharm中运行Django测试