Интеграционные тесты django-channels с помощью pytest?

Я пытаюсь создать простой тестовый фикстур в стиле live-сервера для pytest для тестирования с django-каналами. Я пришел к самому простому решению:

import pytest


@pytest.fixture(scope="function")
def channels_live_server(request):
    from channels.testing import ChannelsLiveServerTestCase

    class MyChannelsLiveServerTestCase(ChannelsLiveServerTestCase):
        @property
        def url(self):
            return self.live_server_url

    server = MyChannelsLiveServerTestCase()
    server._pre_setup()

    yield server

    server._post_teardown()

При использовании веб-сервер запускается в фоновом режиме и обслуживает веб-страницы просто отлично... за исключением того, что он использует "производственные" настройки, что означает, что используемая база данных НЕ является тестовой базой данных.

Есть идеи, как это исправить? Я понимаю, что многопроцессорность на каком-то более позднем этапе использует Popen и запускает сервер, используя контекст spawn. Я на macOS, если это имеет значение.

В Django-chnanels 4.1 проблема с классами по умолчанию на моей установке заключалась в том, что имя тестовой базы данных не задавалось должным образом. Поэтому мне пришлось использовать этот патч, чтобы channels_live_server исправить это в моем коде.

Мое решение - простой и быстрый патч, потому что вся проблема выглядит как часть более серьезной проблемы, когда окружение родительского процесса на самом деле не копируется в окружение DaphneProcess через мультипроцессинг. Или, возможно, некоторые настройки Django опускаются в процессе.

Единственное, что делает этот код, это устанавливает правильное имя базы данных для тестирования, в том числе при использовании с pytest-xdist.

from functools import partial

import pytest
from channels.testing import ChannelsLiveServerTestCase
from daphne.testing import DaphneProcess
from django.db.backends.base.creation import TEST_DATABASE_PREFIX


class PatchedDaphneProcess(DaphneProcess):

    def __init__(self, *args, **kwargs):
        self.test_db_name = kwargs.pop("test_db_name")
        super().__init__(*args, **kwargs)

    def run(self):
        from django.conf import settings

        settings.DATABASES["default"]["NAME"] = self.test_db_name
        return super().run()


class PatchedLiveServerTestCase(ChannelsLiveServerTestCase):
    # ProtocolServerProcess = PatchedDaphneProcess

    def __init__(self, *args, **kw):
        self.test_db_name = kw.pop("test_db_name")
        super().__init__(*args, **kw)

    @property
    def ProtocolServerProcess(self):
        return partial(PatchedDaphneProcess, test_db_name=self.test_db_name)

    @property
    def url(self):
        return self.live_server_url


@pytest.fixture(scope="function")
def channels_live_server(request, transactional_db):
    def test_db_name():
        from django.conf import settings

        n = settings.DATABASES["default"].get("TEST", {}).get("NAME", None)
        if n:
            return n
        if settings.DATABASES["default"]["NAME"].startswith(TEST_DATABASE_PREFIX):
            return settings.DATABASES["default"]["NAME"]

        return TEST_DATABASE_PREFIX + settings.DATABASES["default"]["NAME"]

    server = PatchedLiveServerTestCase(test_db_name=test_db_name())
    server._pre_setup()

    yield server

    server._post_teardown()

Вернуться на верх