sanic-org / sanic-testing

Test clients for Sanic
https://sanic.dev/en/plugins/sanic-testing/getting-started.html
MIT License
31 stars 19 forks source link

Sanic @before_server_start listener is executed multiple times when using SanicASGITestClient with pytest #76

Open tkosman opened 2 months ago

tkosman commented 2 months ago

I'm experiencing an issue while testing a Sanic application asynchronously using pytest. According to the Sanic documentation, the SanicASGITestClient should not spin up a server on every request. However, in my tests, it appears that the @before_server_start event is being run multiple times, which contradicts the expected behavior.

Here is a minimal example to demonstrate the issue:

import pytest
import sanic

def create_app():
    app = sanic.Sanic("foo")

    @app.before_server_start
    def setup(app):
        # print("Setup")
        app.ctx.x = "aaa"

    @app.route("/save")
    def saving(request):
        app.ctx.x = "123"
        return sanic.response.text("saved")

    @app.route("/get")
    def getting(request):
        return sanic.response.text(app.ctx.x)

    return app

@pytest.fixture
def app():
    a = create_app()
    yield a
    a.stop(unregister=True)

@pytest.mark.asyncio
async def test_this(app):
    request, response = await app.asgi_client.get("/save")
    assert response.text == "saved"

    request, response = await app.asgi_client.get("/get")
    assert response.text == "123"

My env:

When running the test, the @before_server_start event seems to be executed more than once (I tried to do example print in that section and it invokes multiple times), resulting in app.ctx.x not retaining the value set in the /save route when subsequently accessed in the /get route.

Should the @before_server_start event behave like this when using SanicASGITestClient? If this behavior is expected, how should I properly test my app to ensure state is maintained between requests during asynchronous testing?