Testing with the Flask Client
To test your application's routes and logic without running a live server, use the Flask test client to simulate requests and inspect responses.
Basic Test Client Usage
The most common way to test is by creating a test client from your application instance. Ensure you set app.testing = True so that exceptions propagate to the test client instead of being handled as generic 500 errors.
import flask
import pytest
def test_index_route():
app = flask.Flask(__name__)
app.testing = True
@app.route("/")
def index():
return "Hello, World!"
client = app.test_client()
response = client.get("/")
assert response.status_code == 200
assert response.data == b"Hello, World!"
Inspecting Request State and Context
By default, the request context is popped as soon as the request finishes. To inspect context locals like flask.request, flask.session, or flask.g after a request, use the client as a context manager.
def test_request_context_preservation(app, client):
@app.route("/set-g")
def set_g():
flask.g.value = 42
return ""
with client:
client.get("/set-g")
# Context is preserved until the 'with' block ends
assert flask.g.value == 42
assert flask.request.path == "/set-g"
Manipulating Sessions
To pre-populate or verify session data, use the session_transaction() method. This requires use_cookies=True (the default) on the test client.
def test_session_data(app, client):
@app.route("/check-session")
def check_session():
return str(flask.session.get("user_id"))
with client:
with client.session_transaction() as sess:
sess["user_id"] = 123
rv = client.get("/check-session")
assert rv.data == b"123"
Testing JSON APIs
The test client simplifies JSON testing by providing a json argument for requests and a get_json() method for responses.
def test_json_echo(app, client):
@app.route("/echo", methods=["POST"])
def echo():
return flask.jsonify(flask.request.get_json())
data = {"key": "value"}
response = client.post("/echo", json=data)
assert response.is_json
assert response.get_json() == data
Simulating Request Environments
If you need to test a function that depends on the request context (like a helper using url_for) without performing a full request dispatch, use test_request_context().
def test_url_generation(app):
with app.test_request_context("/path", method="POST"):
# Now flask.request and flask.url_for work as if in a real request
assert flask.request.path == "/path"
assert flask.request.method == "POST"
Advanced Request Configuration
For complex request setups, you can use EnvironBuilder to construct a WSGI environment manually, or pass specific environment variables to the client's environ_base.
from werkzeug.test import EnvironBuilder
def test_custom_environ(app, client):
# Method 1: Modify client defaults
client.environ_base["REMOTE_ADDR"] = "192.168.0.1"
# Method 2: Use EnvironBuilder for a specific call
builder = EnvironBuilder(app, path="/", method="GET")
builder.headers["X-Custom-Header"] = "Value"
env = builder.get_environ()
response = client.open(env)
Troubleshooting
- Exceptions returning 500: If your tests show a 500 status code instead of the actual exception, ensure
app.testing = Trueis set. This forcesPROPAGATE_EXCEPTIONStoTrue. - Session Transaction Failures: If
session_transaction()raises aRuntimeErrorstating the session backend did not open a session, ensure your application is configured to handle sessions (e.g., aSECRET_KEYis set) and that you are using the client within awithblock. - Context Errors: If you get a
RuntimeErrorabout working outside of request context, ensure you are either usingwith client:for full requests orwith app.test_request_context():for isolated logic.