如何为单元测试设置和拆除临时Django数据库?
我想要一个包含一些单元测试的Python模块,这样我就可以把它传给 hg bisect --command
使用。
这些单元测试是用来测试一个Django应用的某些功能,但我觉得我不能用 hg bisect --command manage.py test mytestapp
,因为 mytestapp
必须在settings.py中启用,而当 hg bisect
更新工作目录时,settings.py的修改会被覆盖。
所以,我想知道下面这样的做法是否是最好的选择:
import functools, os, sys, unittest
sys.path.append(path_to_myproject)
os.environ['DJANGO_SETTINGS_MODULE'] = 'myapp.settings'
def with_test_db(func):
"""Decorator to setup and teardown test db."""
@functools.wraps
def wrapper(*args, **kwargs):
try:
# Set up temporary django db
func(*args, **kwargs)
finally:
# Tear down temporary django db
class TestCase(unittest.TestCase):
@with_test_db
def test(self):
# Do some tests using the temporary django db
self.fail('Mark this revision as bad.')
if '__main__' == __name__:
unittest.main()
如果你能给我一些建议,我将非常感激:
- 是否有更简单的方法,比如说可以继承
django.test.TestCase
而不修改settings.py,或者如果没有的话; - 上面提到的“设置临时Django数据库”和“拆除临时Django数据库”应该怎么写?
2 个回答
5
你必须使用Django内部的TestCase来完成这个任务。
from django.test import TestCase
class TestCase(TestCase):
# before every call to setUp(), the db is automatically
# set back to the state is was after the first syncdb then
# all these fixture files will be loaded in the db
fixtures = ['mammals.json', 'birds']
# put whatever you want here, you don't need to call the
# super()
def setUp(self):
# Test definitions as before.
call_setup_methods()
def test(self):
# Do some tests using the temporary django db
self.fail('Mark this revision as bad.')
它和unittest完全兼容,所以你的代码不需要做太多修改。
你可以了解更多关于 django.test、数据文件、清空数据库 和 加载数据 命令的信息。
如果你想用装饰器来完成这个工作,你可以使用 call_command
在你的Python程序中调用任何Django命令。例如:
from django.core.management import call_command
call_command('flush', 'myapp')
call_command('loaddata', 'myapp')
10
我搞定了!现在我有一个完全独立于任何Django应用的Python文件,可以用测试数据库运行单元测试:
#!/usr/bin/env python
"""Run a unit test and return result.
This can be used with `hg bisect`.
It is assumed that this file resides in the same dir as settings.py
"""
import os
from os.path import abspath, dirname
import sys
import unittest
# Set up django
project_dir = abspath(dirname(dirname(__file__)))
sys.path.insert(0, project_dir)
os.environ['DJANGO_SETTINGS_MODULE'] = 'myproject.settings'
from django.db import connection
from django.test import TestCase
from django.test.utils import setup_test_environment, teardown_test_environment
from myproject import settings
from myproject.myapp.models import MyModel
class MyTestCase(TestCase):
def test_something(self):
# A failed assertion will make unittest.main() return non-zero
# which if used with `hg bisect` will mark the revision as bad
self.assertEqual(0, len(MyModel.objects.all())) # and so on
if '__main__' == __name__:
try:
setup_test_environment()
settings.DEBUG = False
verbosity = 0
old_database_name = settings.DATABASE_NAME
connection.creation.create_test_db(verbosity)
unittest.main()
finally:
connection.creation.destroy_test_db(old_database_name, verbosity)
teardown_test_environment()