Как настроить и демонтировать временный django db для модульного тестирования? - PullRequest
9 голосов
/ 28 марта 2010

Я хотел бы иметь модуль Python, содержащий некоторые модульные тесты, которые я могу передать hg bisect --command.

Модульные тесты тестируют некоторые функциональные возможности приложения django, но я не думаю, что смогу использовать hg bisect --command manage.py test mytestapp, потому что mytestapp должно быть включено в settings.py, а изменения в settings.py закрывается, когда hg bisect обновляет рабочий каталог.

Поэтому я хотел бы знать, является ли что-то вроде следующего лучшим способом:

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" и "Снять временную базу данных django"?

Ответы [ 2 ]

10 голосов
/ 28 марта 2010

взломали его. Теперь у меня есть один файл 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()
5 голосов
/ 28 марта 2010

Для этого вы должны использовать внутренний 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, фикстурах , flush и loaddata .

Если вы хотите использовать декоратор для выполнения этой работы, вы можете использовать call_command, чтобы использовать в вашей программе на python любую команду django. например:

from django.core.management import call_command

call_command('flush', 'myapp')
call_command('loaddata', 'myapp')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...