Единичное тестирование с использованием джанго-трубопровода

У меня есть проблемы с модульным тестированием представлений приложения, использующего django-конвейер? Всякий раз, когда я выполняю client.get() на любом URL-адресе, он создает следующее исключение:

ValueError: файл css/bootstrap.css не найден с объектом < конвейер .storage.PipelineCachedStorage в 0x10d544950 > .

Тот факт, что это bootstrap.css, конечно, не имеет значения, но что я не могу выполнить рендеринг представления из-за этого исключения.

Приглашаем всех гидов/советов!

Ответ 1

У меня возникла аналогичная проблема. Однако установка

STATICFILES_STORAGE='pipeline.storage.NonPackagingPipelineStorage'

при запуске тестов только частично решена моя проблема. Я также должен был полностью отключить конвейер, если вы хотите запустить тесты LiverServerTestCase, не называя "collectcstatic" перед запуском тестов:

PIPELINE_ENABLED=False

Так как django 1.4 довольно легко модифицировать настройки для тестов - есть удобный декоратор, который работает для методов или классов TestCase:

https://docs.djangoproject.com/en/1.6/topics/testing/tools/#overriding-settings

например.

from django.test.utils import override_settings

@override_settings(STATICFILES_STORAGE='pipeline.storage.NonPackagingPipelineStorage', PIPELINE_ENABLED=False)
class BaseTestCase(LiveServerTestCase):
    """
    A base test case for Selenium
    """

    def setUp(self):
        ...

Однако это привело к непоследовательным результатам, как описывает @jrothenbuhler в своем ответе. Несмотря на это, это не так идеально, если вы используете интеграционные тесты - вы должны максимально имитировать производство, чтобы поймать любые потенциальные проблемы. Похоже, django 1.7 имеет решение для этого в виде нового тестового примера "StaticLiveServerTestCase". Из документов: https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#django.contrib.staticfiles.testing.StaticLiveServerCase

Этот подкласс Unittest TestCase расширяется django.test.LiveServerTestCase.

Как и его родитель, вы можете использовать его для написания тестов, которые включают запуская тестируемый код и потребляя его с помощью инструментов тестирования через HTTP (например, Selenium, PhantomJS и т.д.), из-за чего его необходимо, чтобы статические активы также были опубликованы.

Я не тестировал это, но звучит многообещающе. На данный момент я делаю то, что @jrothenbuhler в его решении использует пользовательский тестовый бегун, который не требует, чтобы вы запускали collectstatic. Если вы действительно хотите запустить коллекцию, вы можете сделать что-то вроде этого:

from django.conf import settings
from django.test.simple import DjangoTestSuiteRunner
from django.core.management import call_command

class CustomTestRunner(DjangoTestSuiteRunner):
    """
    Custom test runner to get around pipeline and static file issues
    """

    def setup_test_environment(self):
        super(CustomTestRunner, self).setup_test_environment()
        settings.STATICFILES_STORAGE = 'pipeline.storage.NonPackagingPipelineStorage'
        call_command('collectstatic', interactive=False)

В settings.py

TEST_RUNNER = 'path.to.CustomTestRunner'

Ответ 2

Я столкнулся с той же проблемой. Я занимался этим с помощью специального тестового бегуна:

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

from pipeline.conf import settings as pipeline_settings

class PipelineOverrideRunner(DjangoTestSuiteRunner):

    def setup_test_environment(self):
        '''Override STATICFILES_STORAGE and pipeline DEBUG.'''
        super(PipelineOverrideRunner, self).setup_test_environment()
        settings.STATICFILES_STORAGE = 'pipeline.storage.PipelineFinderStorage'
        pipeline_settings.DEBUG = True

Затем в вашем settings.py:

TEST_RUNNER = 'path.to.PipelineOverrideRunner'

Настройка параметра DEBUG для конвейера в True означает, что статические файлы не упакованы. Это предотвращает необходимость запуска collectstatic перед запуском тестов. Обратите внимание, что это настройка DEBUG конвейера, а не Django's, которая здесь переопределяется. Причина этого в том, что вы хотите, чтобы Django DEBUG был False при тестировании, чтобы лучше всего имитировать производственную среду.

Настройка STATICFILES_STORAGE в PipelineFinderStorage делает это так, чтобы статические файлы находились, когда для параметра Django DEBUG установлено значение False, как и при выполнении тестов.

Причина, по которой я решил переопределить эти параметры в пользовательском тестовом runner, а не в пользовательской TestCase, состоит в том, что определенные вещи, такие как объект django.contrib.staticfiles.storage.staticfiles_storage, устанавливаются один раз на основе этих и других настройки. При использовании настраиваемой TestCase я столкнулся с проблемами, когда тесты проходили и терпели неудачу в зависимости от того, произошло ли переопределение, когда были загружены модули, такие как django.contrib.staticfiles.storage.

Ответ 3

Я столкнулся с той же проблемой. Мне удалось обойти это, используя другой STATIC_FILES_STORAGE, когда я тестирую:

STATICFILES_STORAGE = 'pipeline.storage.NonPackagingPipelineStorage'

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

- EDIT

Потребовалось немного больше усилий, потому что это может присутствовать только во время unittesting. Для этого я использовал фрагмент http://djangosnippets.org/snippets/1011/ и создал класс UITestCase:

class UITestCase(SettingsTestCase):
    '''
    UITestCase handles setting the Pipeline settings correctly.
    '''
    def __init__(self, *args, **kwargs):
        super(UITestCase, self).__init__(*args, **kwargs)

    def setUp(self):
        self.settings_manager.set(
            STATICFILES_STORAGE='pipeline.storage.NonPackagingPipelineStorage')

Теперь все мои тесты, которые должны отображать пользовательский интерфейс, которые включают теги compress_css, используют UITestCase вместо django.test.TestCase.

Ответ 4

Я столкнулся с той же проблемой, и оказалось, что у меня был

TEST_RUNNER = 'djcelery.contrib.test_runner.CeleryTestSuiteRunner'

Я не понимаю, как, но он должен каким-то образом взаимодействовать с Pipeline. Как только я удалил эту настройку, проблема исчезла.

Мне все еще нужно было заставить Сельдерей проявлять нетерпение во время тестирования, поэтому я использовал override_settings для тестов, которые ему нужны:

from django.test.utils import override_settings

…

class RegisterTestCase(TestCase):

    @override_settings(CELERY_EAGER_PROPAGATES_EXCEPTIONS=True,
                       CELERY_ALWAYS_EAGER=True,
                       BROKER_BACKEND='memory')
    def test_new(self):
        …

Ответ 5

То же самое здесь. Относится к этим вопросам: https://github.com/cyberdelia/django-pipeline/issues/277

Поскольку я использую py.test, я помещаю это в conftest.py в качестве обходного пути:

import pytest
from django.conf import settings

def pytest_configure():
    # workaround to avoid django pipeline issue
    # refers to 
    settings.STATICFILES_STORAGE = 'pipeline.storage.PipelineStorage'

Ответ 6

я пробовал обходной путь @jrothenbuhler, и сначала это помогает.. но потом, по какой-то причине, он снова начинает работать с той же ошибкой после нескольких часов отладки я понял, что единственное, что помогает, это установить

STATICFILES_STORAGE = 'pipeline.storage.NonPackagingPipelineStorage'

прямо в настройках... не знаю почему, но это работает.