简体   繁体   English

ChannelsLiveServerTestCase 相当于 pytest

[英]ChannelsLiveServerTestCase equivalent for pytest

In pytest-django there is a builtin fixture live_server though it seems like this server (that is actually based on LiveServerTestCase ) can't handle web-sockets or at least won't interact with my asgi.py module.在 pytest-django 中有一个内置夹具live_server虽然看起来这个服务器(实际上是基于LiveServerTestCase )无法处理网络套接字或者至少不会与我的asgi.py模块交互。

How can one mimic that fixture in order to use ChannelsLiveServerTestCase instead?怎样才能模仿那个夹具以便改用ChannelsLiveServerTestCase Or anything else that will run a test-database and will be able to serve an ASGI application?或者其他任何可以运行测试数据库并能够为 ASGI 应用程序提供服务的东西?

My goal eventually is to have as close to production environment as possible, for testing and being able to test interaction between different Consumers.我的最终目标是尽可能接近生产环境,用于测试并能够测试不同消费者之间的交互。

PS: I know I can run manage.py testserver <Fixture> on another thread / process by overriding django_db_setup though I seek for a better solution. PS:我知道我可以通过覆盖django_db_setup在另一个线程/进程上运行manage.py testserver <Fixture>尽管我寻求更好的解决方案。

You can implement a channels_live_server fixture based on the implementations of:您可以基于以下实现来实现channels_live_server fixture:

@medihack implemented it at https://github.com/pytest-dev/pytest-django/issues/1027 : @medihackhttps://github.com/pytest-dev/pytest-django/issues/1027实现了它:

 from functools import partial from channels.routing import get_default_application from daphne.testing import DaphneProcess from django.contrib.staticfiles.handlers import ASGIStaticFilesHandler from django.core.exceptions import ImproperlyConfigured from django.db import connections from django.test.utils import modify_settings def make_application(*, static_wrapper): # Module-level function for pickle-ability application = get_default_application() if static_wrapper is not None: application = static_wrapper(application) return application class ChannelsLiveServer: host = "localhost" ProtocolServerProcess = DaphneProcess static_wrapper = ASGIStaticFilesHandler serve_static = True def __init__(self) -> None: for connection in connections.all(): if connection.vendor == "sqlite" and connection.is_in_memory_db(): raise ImproperlyConfigured( "ChannelsLiveServer can not be used with in memory databases" ) self._live_server_modified_settings = modify_settings(ALLOWED_HOSTS={"append": self.host}) self._live_server_modified_settings.enable() get_application = partial( make_application, static_wrapper=self.static_wrapper if self.serve_static else None, ) self._server_process = self.ProtocolServerProcess(self.host, get_application) self._server_process.start() self._server_process.ready.wait() self._port = self._server_process.port.value def stop(self) -> None: self._server_process.terminate() self._server_process.join() self._live_server_modified_settings.disable() @property def url(self) -> str: return f"http://{self.host}:{self._port}" @pytest.fixture def channels_live_server(request): server = ChannelsLiveServer() request.addfinalizer(server.stop) return server

couldn't get @aaron's solution to work with websockets, this solution suffice though:无法让@aaron 的解决方案与 websockets 一起工作,但这个解决方案就足够了:

import threading
import time

from functools import partial

from django.contrib.staticfiles.handlers import ASGIStaticFilesHandler
from django.core.exceptions import ImproperlyConfigured
from django.db import connections
from django.test.utils import modify_settings

from daphne.server import Server as DaphneServer
from daphne.endpoints import build_endpoint_description_strings


def get_open_port() -> int:
    import socket
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind(("", 0))
    s.listen(1)
    port = s.getsockname()[1]
    s.close()
    return port


def make_application(*, static_wrapper):
    # Module-level function for pickle-ability
    if static_wrapper is not None:
        application = static_wrapper(your_asgi_app)
    return application


class ChannelsLiveServer:
    port = get_open_port()
    host = "localhost"
    static_wrapper = ASGIStaticFilesHandler
    serve_static = True

    def __init__(self) -> None:
        for connection in connections.all():
            if connection.vendor == "sqlite" and connection.is_in_memory_db():
                raise ImproperlyConfigured(
                    "ChannelsLiveServer can not be used with in memory databases"
                )

        self._live_server_modified_settings = modify_settings(ALLOWED_HOSTS={"append": self.host})
        self._live_server_modified_settings.enable()

        get_application = partial(
            make_application,
            static_wrapper=self.static_wrapper if self.serve_static else None,
        )
        endpoints = build_endpoint_description_strings(
            host=self.host, port=self.port
        )

        self._server = DaphneServer(
            application=get_application(),
            endpoints=endpoints
        )
        t = threading.Thread(target=self._server.run)
        t.start()
        for i in range(10):
            time.sleep(0.10)
            if self._server.listening_addresses:
                break
        assert self._server.listening_addresses[0]

    def stop(self) -> None:
        self._server.stop()
        self._live_server_modified_settings.disable()

    @property
    def url(self) -> str:
        return f"ws://{self.host}:{self.port}"

    @property
    def http_url(self):
        return f"http://{self.host}:{self.port}"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM