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