在内存中运行Django MySQL测试
我有一个使用mysql作为后端的django 1.4项目。我已经设置好测试在内存中运行。
if 'test' in sys.argv:
DATABASES['default'] = {'ENGINE': 'django.db.backends.sqlite3'}
问题是我需要使用mysql的一些功能(全文索引)。
有没有办法让django在测试时使用内存中的MySQL?
我的项目依赖于全文索引。在开发项目时,我会先运行syncdb,然后执行一个.sql
文件来创建全文索引。
我希望在我测试的函数中使用django的ORM进行全文搜索。我尝试在每个测试的初始化时手动添加全文索引,比如:
cursor.execute('alter table mytable add fulltext(one, two)')
但是在使用sqlite时这不起作用(我认为是因为sqlite不支持全文索引)。
上面的sql在我去掉内存测试时是可以工作的。我喜欢内存测试的速度。有没有办法让我在内存中运行mysql?
人们是如何测试依赖于数据库特定功能的应用程序的?比如全文索引或地理信息系统等……他们是否必须在文件系统上正常运行测试?
谢谢
3 个回答
正如monkut在问题评论中提到的,如果你把测试数据库放在一个内存驱动器上,比如在Linux上使用tmpfs文件系统,可能会让MySql的速度更快。不过,如果你担心测试时的速度,其实这可能不会有太大改善,因为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
接着,设置settings.test.mysql
和settings.test.sqlite
,并配置不同的DATABASE
设置。如果你用settings.test.sqlite
来执行测试,那么依赖于MySql特定功能的测试会被跳过;但如果你用settings.test.mysql
来运行测试,这些测试就会执行。
这种方法让你可以针对特定的数据库后端进行测试,同时在开发过程中也能灵活地对大多数测试使用更快的SQLite数据库。
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'
}
}
}
但是根据官方文档的说法:
MEMORY tables cannot contain BLOB or TEXT columns.
所以我觉得对于你(以及很多其他人)的使用场景来说,这个功能可能没什么用。
我在这个讨论串中找到了一些加速MySQL测试的其他建议。一定要看看Daniel Roseman关于使用INNODB
引擎的回答。
别去测试MySQL。MySQL已经由它的开发者测试过了。你的工作是写代码,让你可以用一个模拟的Python对象来替代MySQL的连接,这个模拟对象会返回MySQL本来会返回的结果(或者检查一下发送给MySQL的查询是否是你想要的那样)。