In the previous post we got a glimpse of pytest. In this post, we’ll be diving a little deeper. To do this, we’ll be build a basic Flask app.
Before we start coding though, let’s first set up our directory structure. Thankfully, pytest gives us a few examples in their Directory Structure and Good Practices pages. For the purposes of this post, we’ll use this structure:
.
├── requirements-dev.txt
├── requirements.txt
├── setup.py
├── src
│ └── app.py
└── tests
├── app_test.py
└── conftest.py
Now that our structure is done, we need to fill in each of the files.
In the requirements.txt file, we’ll add flask as it is a dependency for our project:
flask
In the requirements-dev.txt file, we’ll add the following two lines. This makes it easy for devs to get started:
pytest
-r requirements.txt
As we’re devs ourselves, we’ll need to install these dependencies. To do that, we issue the following command:
pip3 install -r requirements-dev.txt
Now we need to write the contents of our setup.py file. As outlined in the pytest documentation, the following is necessary at a minimum:
1
2
3
from setuptools import setup, find_packages
setup(name="FlaskApp", packages=find_packages())
Once that’s done, we need to “install” our app in “editable” mode. We do this by issuing the following command:
pip install -e .
Now that we’ve got all the prep out of the way, we’re ready to start coding our app. Let’s put the following code in app.py:
1
2
3
4
5
6
7
8
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return 'OK'
To make sure our app works, let’s run the following commands:
FLASK_APP=src/app.py flask run
When we browse to 127.0.0.1:5000, we see an “OK” message returned. Great, it works!
Let’s now get to work on setting up testing for our app.
Note: The inspiration for our test app comes from the flask documentation.
In conftest.py add the following:
1
2
3
4
5
6
7
8
9
10
from src.app import app
import pytest
@pytest.fixture
def client():
app.testing = True
app.config['DEBUG'] = True
with app.test_client() as client:
yield client
See this page for more information on conftest.py.
We’ve doing a few things in this block of code, so let’s pause for a moment and analyse it:
-
We’re using the
test_client()method - this enables us to test our Flask app -
We’re then using a
yield- this ensures our client stays up while we’re using it for testing -
Finally, we’ve wrapped the whole thing a
fixture- this enables us to use the client in our tests, as we’ll see in a moment
In app_test.py, we add the following:
1
2
3
def test_index(client):
r = client.get('/')
assert r.status == '200 OK'
As you can see, we’ve passed the client fixture to our test_index test. We’re then using the client’s get method to call our / route. This results in a response_class object being returned. We then assert that the status of the response to make sure it’s 200 OK.
The assert is what makes or breaks our test. If the assertion is correct, the test passes. Otherwise it fails.
It’s now time to run our test:
$ pytest -v
=============================== test session starts ================================
platform linux -- Python 3.8.0, pytest-5.4.3, py-1.8.1, pluggy-0.13.1 -- /home/wrobinson/Development/python-tdd/venv/bin/python
cachedir: .pytest_cache
rootdir: /home/wrobinson/Development/python-tdd
collected 1 item
tests/app_test.py::test_index PASSED [100%]
================================ 1 passed in 0.02s =================================
As always, if you have any questions or have a topic that you would like me to discuss, please feel free to post a comment at the bottom of this blog entry, e-mail at will@oznetnerd.com, or drop me a message on Reddit (OzNetNerd).
Note: The opinions expressed in this blog are my own and not those of my employer.
Leave a comment