Skip to main content

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 = True is set. This forces PROPAGATE_EXCEPTIONS to True.
  • Session Transaction Failures: If session_transaction() raises a RuntimeError stating the session backend did not open a session, ensure your application is configured to handle sessions (e.g., a SECRET_KEY is set) and that you are using the client within a with block.
  • Context Errors: If you get a RuntimeError about working outside of request context, ensure you are either using with client: for full requests or with app.test_request_context(): for isolated logic.