Как элегантно поменять (исправить) параметр Django FileSystemStorage в ваших модульных тестах? - PullRequest
4 голосов
/ 02 февраля 2011

Я столкнулся со следующей проблемой.У меня есть модель, которая выглядит примерно так:

class Package(models.Model):
    name = models.CharField(max_length=64)
    file = models.FileField(upload_to="subdir",
                            storage=settings.PACKAGE_STORAGE,
                            null=True)

Существенным в этом примере является аргумент storage= для конструктора FileField.Заполняется значением от settings.py.Там есть следующий код:

from django.core.files.storage import FileSystemStorage
PACKAGE_STORAGE = FileSystemStorage(location="/var/data", base_url="/")

Для производственного использования, это прекрасно работает.Но в моих модульных тестах загружаемые файлы теперь записываются в /var/data, который содержит производственные данные.Я пытался поменять PACKAGE_STORE в packages/tests.py следующим образом

from django.conf import settings     # This is line 1
from tempfile import mkdtemp
settings.PACKAGE_STORAGE = FileSystemStorage(location=mkdtemp(), base_url="/")

# rest of the imports and testing code below

, но реальная проблема заключается в том, что до загружается тестовый файл, приложение packages и егомодели уже загружены, и поэтому настройка PACKAGE_STORAGE была разрешена до того, как я смог изменить ее в коде настройки теста.

Существует ли элегантный способ переопределить этот конкретный параметр в тестированииконтекст?

Ответы [ 4 ]

8 голосов
/ 02 февраля 2011

Не знаю, считается ли это элегантным, но вы можете использовать другой файл настроек для тестирования ...

Что-то вроде:

# test_settings.py

from settings import *

PACKAGE_STORAGE = FileSystemStorage(location='/test/files', base_url="/")

Затем запустите тест, используя настройки теста, python manage.py test --settings=test_settings.

3 голосов
/ 02 февраля 2011

если вы запустите тест через django, это должно сработать

if 'test' in sys.argv:
    settings.DEFAULT_FILE_STORAGE = FileSystemStorage(location=mkdtemp(), base_url="/")

конечно после;)

DEFAULT_FILE_STORAGE = FileSystemStorage(location="/var/data", base_url="/")
2 голосов
/ 30 апреля 2012

Я только что решил эту проблему, добавив в свой пользовательский тестовый запуск. Чтобы узнать, как добавить пользовательский тестовый прогон, см. Определение тестового бегуна в документации Django. Мой код выглядит примерно так:

import shutil
import tempfile
from django.test.simple import DjangoTestSuiteRunner
from django.conf import settings

class CustomTestRunner(DjangoTestSuiteRunner):

    def setup_test_environment(self, **kwargs):
        super(CustomTestRunner, self).setup_test_environment(**kwargs)
        self.backup = {}
        self.backup['DEFAULT_FILE_STORAGE'] = settings.DEFAULT_FILE_STORAGE
        settings.DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
        self.backup['MEDIA_ROOT'] = settings.MEDIA_ROOT
        self.temp_media_root = tempfile.mkdtemp(prefix="myapp-tests")
        settings.MEDIA_ROOT = self.temp_media_root

    def teardown_test_environment(self, **kwargs):
        super(CustomTestRunner, self).teardown_test_environment(**kwargs)
        for name, value in self.backup.iteritems():
            setattr(settings, name, value)

    def run_tests(self, test_labels, **kwargs):
        try:
            test_results = super(CustomTestRunner, self).run_tests(test_labels, **kwargs)
        finally:
            shutil.rmtree(self.temp_media_root, ignore_errors=True)

Это переопределяет некоторые из пользовательских методов набора тестов. setup_test_environment создает резервную копию предыдущих настроек и сохраняет их в атрибуте класса. teardown_test_environment возвращает их к тому, что они были раньше. Метод run_tests использует блок try / finally, чтобы убедиться, что временный каталог удаляется после тестов, даже если возникает исключение.

2 голосов
/ 02 февраля 2011

Переопределить базовую реализацию хранилища для экземпляров FileField в вашей модели динамически:

def setUp(self):
     self._field = Package._meta.get_field_by_name('file')[0]
     self._default_storage = self._field.storage
     test_storage = FileSystemStorage(location=mkdtemp(),
                                      base_url="/")

     self._field.storage = test_storage

def tearDown(self):
     self._field = self._default_storage
...