Flask

Testing

Testing our Hello World app

Introduction

In this minimalist example, using pytest we’re going to test that indeed our Hello World app does return “Hello, World!” with an HTTP OK status code of 200, when hit with a GET request on the URL /

First let’s install pytest into our virtualenv

pip install pytest

And just for reference, this our hello world app:

# hello.py
from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello():
    return 'Hello, World!'

Defining the test

Along side our hello.py, we define a test module called test_hello.py that is going to be discovered by py.test

# test_hello.py
from hello import app

def test_hello():
    response = app.test_client().get('/')

    assert response.status_code == 200
    assert response.data == b'Hello, World!'

Just to review, at this point our project structure obtained with the tree command is:

.
├── hello.py
└── test_hello.py

Running the test

Now we can run this test with the py.test command that will automatically discover our test_hello.py and the test function inside it

$ py.test

You should see some output and an indication that 1 test has passed, e.g.

=== test session starts ===
collected 1 items 
test_hello.py .
=== 1 passed in 0.13 seconds ===

Testing a JSON API implemented in Flask

This example assumes you know how to test a Flask app using pytest

Below is an API that takes a JSON input with integer values a and b e.g. {"a": 1, "b": 2}, adds them up and returns sum a + b in a JSON response e.g. {"sum": 3}.

# hello_add.py
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/add', methods=['POST'])
def add():
    data = request.get_json()
    return jsonify({'sum': data['a'] + data['b']})

Testing this API with pytest

We can test it with pytest

# test_hello_add.py
from hello_add import app
from flask import json

def test_add():        
    response = app.test_client().post(
        '/add',
        data=json.dumps({'a': 1, 'b': 2}),
        content_type='application/json',
    )

    data = json.loads(response.get_data(as_text=True))

    assert response.status_code == 200
    assert data['sum'] == 3

Now run the test with py.test command.

Accessing and manipulating session variables in your tests using Flask-Testing

Most of the web applications use the session object to store some important information. This examples show how you can test such application using Flask-Testing. Full working example is also available on github.

So first install Flask-Testing in your virtualenv

pip install flask_testing

To be able to use the session object you have to set the secret key

app.secret_key = 'my-seCret_KEy'

Let’s imagine you have in your application function that need to store some data in session variables like this

@app.route('/getSessionVar', methods=['GET', 'POST'])
def getSessionVariable():
  if 'GET' == request.method:
    session['sessionVar'] = 'hello'
  elif 'POST' == request.method:
    session['sessionVar'] = 'hi'
  else:
    session['sessionVar'] = 'error'

  return 'ok'

To test this function you can import flask_testing and let your test class inherit flask_testing.TestCase. Import also all the necessary libraries

import flask
import unittest
import flask_testing
from myapp.run import app
    
class TestMyApp(flask_testing.TestCase):

Very important before you start testing is to implement the function create_app otherwise there will be exception.

  def create_app(self):
    return app

To test your application is working as wanted you have a couple of possibilities. If you want to just assure your function is setting particular values to a session variable you can just keep the context around and access flask.session

def testSession1(self):
    with app.test_client() as lTestClient:
      lResp= lTestClient.get('/getSessionVar')
      self.assertEqual(lResp.status_code, 200)
      self.assertEqual(flask.session['sessionVar'], 'hello')

One more useful trick is to differentiate between GET and POST methods like in the next test function

def testSession2(self):
    with app.test_client() as lTestClient:
      lResp= lTestClient.post('/getSessionVar')
      self.assertEqual(lResp.status_code, 200)
      self.assertEqual(flask.session['sessionVar'], 'hi')

Now imagine your function expects a session variable to be set and reacts different on particular values like this

@app.route('/changeSessionVar')
def changeSessionVariable():
  if session['existingSessionVar'] != 'hello':
    raise Exception('unexpected session value of existingSessionVar!')

  session['existingSessionVar'] = 'hello world'
  return 'ok'

To test this function you have to use so called session transaction and open the session in the context of the test client. This function is available since Flask 0.8

def testSession3(self):
    with app.test_client() as lTestClient:
      #keep the session
      with lTestClient.session_transaction() as lSess:
        lSess['existingSessionVar'] = 'hello'

      #here the session is stored
      lResp = lTestClient.get('/changeSessionVar')
      self.assertEqual(lResp.status_code, 200)
      self.assertEqual(flask.session['existingSessionVar'], 'hello world')

Running the tests is as usual for unittest

if __name__ == "__main__":
    unittest.main()

And in the command line

python tests/test_myapp.py

Another nice way to run your tests is to use unittest Discovery like this:

python -m unittest discover -s tests

This modified text is an extract of the original Stack Overflow Documentation created by the contributors and released under CC BY-SA 3.0 This website is not affiliated with Stack Overflow