teardown_request called twice during test
opened this issue · comments
repoduce code example
import pytest
from flask import Flask
def create_app():
app = Flask(__name__)
@app.route("/hello")
def hello():
return "Hello world"
@app.teardown_request
def teardown_request_func(error=None):
print("teardown_request is running!")
return app
@pytest.fixture
def app():
return create_app()
def test_hello(client):
response = client.get('/hello')
assert response.status_code == 200
then execute py.test -s
the test got output like the following
platform darwin -- Python 3.7.6, pytest-6.0.1, py-1.9.0, pluggy-0.13.1
rootdir: /Users/eruda/scripts/fsk
plugins: pylama-7.7.1, flask-1.0.0, cov-2.5.1, pylava-0.2.2
collected 1 item
test_healthz.py .teardown_request is running!
teardown_request is running!
In [3]: pytest_flask.__version__
Out[3]: '1.0.0'
was i doing something wrong ? thanks in advance.
Take this with a grain of salt, but I suspect this is happening because of the second RequestContext that pytest-flask creates and pushes in order to expose url_for
, session
, etc. in your test scope. From flask docs on teardown_request we see that it
Register a function to be run at the end of each request, ....
These functions are executed when the request context is popped...
So I think your teardown code is being executed the first time upon conclusion of client.get('/hello')
and a second time when the context pushed by pytest-flask is popped.
Just adding some code to backup my previous guess
pytest_flask.plugin._push_request_context
@pytest.fixture(autouse=True)
def _push_request_context(request):
# (snip)...
ctx = app.test_request_context()
# let's add this so we can identify this request context instance
ctx.session = "pytest-flask-session"
ctx.push()
Your example, only tweaked a little bit
def create_app():
# (snip)...
@app.route("/hello")
def hello():
# let's add this so we can identify this request context instance
_request_ctx_stack.top.session = "hello_view_context"
return "Hello world"
# (snip)...
Running pytest:
tests/double_teardown.py .teardown_request is running for context hello_view_context
teardown_request is running for context pytest-flask-session
From that we can see we have two separate request contexts and your teardown code is running once for each context.
So I don't think you are doing anything wrong (unless there's some unmentioned/unknown side effect I'm not seeing). I'll close the issue for the time being.
Thanks