Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why use Flask's app.test_client() over requests.Session() for testing

If requests.Session() can handle cookies and does almost everything that app.test_client() does. Then why use the app.test_client()?

like image 965
Charming Robot Avatar asked Aug 26 '18 16:08

Charming Robot


2 Answers

After a bit of digging around, I think I found a good reason to use app.test_client() as well as some other context managers that are provided by Flask.

Test Client

app.test_client()

Enables you to access local contexts via its context manager This is extremely helpful when trying to access variables on the _request_ctx_stack (request context stack). e.g. the request and session context locals.

Some extensions also store variables on the _request_ctx_stack. e.g. flask_login stores the current_user and flask_stateless_auth stores the current_stateless_user on the request context stack.

from flask import request
from flask_stateless_auth import current_stateless_user

with app.test_client() as c:
  test_path = '/resource_for_authenticated_users'
  c.get(test_path)
  assert request.path == test_url
  assert flask.session is not None # You can also access the session context local from here
  assert current_stateless_user is not None

If this was called without the test_client() context manager, it would throw a runtime error for trying to access the request local context after the _request_ctx_stack has been popped. Also, current_stateless_user would return None

App Context

app.app_context()

Similarly, you can access variables that are stored on the app context via the app.app_context() context manager, as such:

from my_app.db import db # db connections are commonly stored on the `_app_ctx_stack`

with app.app_context():
  db.create_tables()
  assert db.session
  assert db.query.MyTable.all()

You can also access app context global variable (typically used to store app related global variables that are not be used across multiple requests like the session global)

with app.app_context():
  assert g.my_global_app_var

Test Request Context

test_request_context()

Then you have the app.test_request_context() context manager which is used to activate a request context temporarily. This is best explained by the official docs.

Session Transaction Context

app.test_client().session_transaction()

Finally, there's the session_transaction() context manager. This is typically used to modify a session object. This should be nested in an app.test_client().

When the __exit__() method is called, the session is safely stored.

example from docs:

with app.test_client() as c:
     with c.session_transaction() as sess:
         sess['a_key'] = 'a value'

    # once this is reached the session was stored
like image 87
Charming Robot Avatar answered Oct 12 '22 12:10

Charming Robot


test_client is already prebuilt into flask, this makes it easier for people to quickly test their programs. Both the requests utility and test_client server the same functionality, so the usage is just based on personal preference.

like image 34
msmith Avatar answered Oct 12 '22 13:10

msmith