pytest-django
pytest-django copied to clipboard
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.
How can one mimic that fixture in order to use ChannelsLiveServerTestCase instead? Or anything else that will run a test-database and will be able to serve an ASGI application?
My goal eventually is to have as close to production environment as possible, for testing and being able to test interaction between different Consumers.
I tried some stuff, but couldn't get it to work. Maybe someone can take a look: https://github.com/django/daphne/discussions/451
Got it finally working with Channels / Daphne 4.0.0:
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_liver_server(request):
server = ChannelsLiveServer()
request.addfinalizer(server.stop)
return server
what's request?
def channels_liver_server(request):
what's request?
def channels_liver_server(request):
A built in fixture of pytest, see https://docs.pytest.org/en/7.1.x/reference/reference.html#request
@medihack Is this already implemented as fixture in Pytest? I cannot find it there.
@flaiming Nope, I don't think so, and not sure if the pytest-django team is interested (maybe because of the additional channels dependency). That said, I have been using it as a custom fixture until now without a problem.
Any info on how to get the code above working with selenium browser logins? After adding the cookie, everything seems to work fine but as soon, as I browser.refresh()
, my authentication cookie in sessionid
is gone, despite there being a valid Session
object in the database.
I also had to manually create my defined test database from test.py
in Postgres for it to work, as it somehow didn't seem to create it automatically with asgiref.
@pytest.fixture
def browser(request):
""" Selenium webdriver fixture """
options = webdriver.ChromeOptions()
browser_ = webdriver.Chrome(options=options)
yield browser_
browser_.quit()
@pytest.fixture
def authenticated_browser_staff(browser, client, channels_live_server, user_staff):
""" Return a browser instance with logged-in user session. """
browser.get(channels_live_server.url)
client.get(channels_live_server.url)
client.force_login(user_staff)
browser.add_cookie({
'name': settings.SESSION_COOKIE_NAME,
'value': client.cookies[settings.SESSION_COOKIE_NAME].value,
'expires': None,
'secure': False,
'path': '/'
})
browser.refresh()
assert any(c for c in browser.get_cookies() if c['name'] == settings.SESSION_COOKIE_NAME)
return browser
see this SO https://stackoverflow.com/questions/73140518/channelsliveservertestcase-equivalent-for-pytest/75046701#75046701
Doesn't work using both channels_live_server_thread
and channels_live_server_proc
from your POC https://github.com/nrbnlulu/channels_pytest_liveserver/blob/master/tests/test_liveserver.py
Make sure you have database access... Also what is the error (if any)?
I realized while my user_staff
is passed to authenticated_browser_staff
correctly (with a pk etc) and I can authenticate them using client
, the browser + daphne server cannot create / access the test database.
Can it have something to do with make_application
and it somehow re-initializing the Django app or Daphne running in a different thread, thus not keeping the test database alive?