[英]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:
live_server
fixture, which instantiates live_server
fixture,它实例化
LiveServer
helper, which starts LiveServerThread
, andLiveServerThread
的LiveServer
助手,以及ChannelsLiveServerTestCase
, which starts DaphneProcess
. ChannelsLiveServerTestCase
,启动DaphneProcess
。 @medihack implemented it at https://github.com/pytest-dev/pytest-django/issues/1027 : @medihack在https://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.