如何设置和拆卸临时django db进行单元测试?

时间:2010-03-28 15:41:28

标签: python django unit-testing mercurial

我想有一个包含一些单元测试的python模块,我可以传递给hg bisect --command

单元测试正在测试django应用的一些功能,但我认为我不能使用hg bisect --command manage.py test mytestapp,因为必须在settings.py中启用mytestapp,并对设置进行编辑当hg bisect更新工作目录时,.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()

如果您能提出建议,我将非常感激:

  1. 如果有一种更简单的方法,可能是继承django.test.TestCase,但不能编辑settings.py,如果没有;
  2. 上面说“设置临时django db”和“拆除临时django db”应该是什么?

2 个答案:

答案 0 :(得分:10)

破解了。我现在有一个python文件完全独立于任何可以使用测试数据库运行单元测试的django应用程序:

#!/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()

答案 1 :(得分: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, fixturesflushloaddata命令。

如果您确实想使用装饰器来完成这项工作,您可以使用call_command在您的python程序中使用任何django命令。例如:

from django.core.management import call_command

call_command('flush', 'myapp')
call_command('loaddata', 'myapp')