Skip to content

Instantly share code, notes, and snippets.

@eruvanos
Created February 26, 2020 09:03
Show Gist options
  • Save eruvanos/c370b04e1be18b89d1babec188495c32 to your computer and use it in GitHub Desktop.
Save eruvanos/c370b04e1be18b89d1babec188495c32 to your computer and use it in GitHub Desktop.
Run Flask app as fixture
from threading import Thread
import pytest
import requests
from flask import Flask
@pytest.fixture()
def app() -> Flask:
host = 'localhost'
port = 5000
# Create app with shutdown hook
app = Flask(__name__)
app.env = 'development'
app.testing = True
@app.route('/shutdown')
def shutdown():
from flask import request
request.environ['werkzeug.server.shutdown']()
return 'OK', 200
# Start server
thread = Thread(target=app.run, daemon=True, kwargs=dict(host=host, port=port))
thread.start()
# Provide app for testing
yield app
# Shutdown server
requests.get('http://localhost:5000/shutdown')
thread.join()
def test_flask(app):
@app.route('/ping')
def ping():
return 'PONG'
requests.get('http://localhost:5000/ping').raise_for_status()
@mihaitodor
Copy link

Since werkzeug.server.shutdown has been deprecated and removed, the above no longer works. However, if you only need the server to start once before running the tests (at the session level), then you can skip thread.join() because, when the tests finish, it will be the only thread left running and the Python process exits when only daemon threads are left. Details here: https://docs.python.org/3/library/threading.html#thread-objects

This is the code ended up with in my conftest.py:

@pytest.fixture(scope='session')
def app():
    app = create_app()

    thread = Thread(target=app.run, daemon=True, kwargs=dict(host='localhost', port=5000))
    thread.start()

    yield app


@pytest.fixture(scope='module')
def client(app):
    return app.test_client()

All the tests which need this full-fledged Flask server to be up and running must to use the client fixture which depends on the app fixture. For example:

def test_ping(client):
    response = client.get('http://localhost:5000/ping')

    assert response.status_code == 200

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment