Python series (4 Part Series)
1 How to add basic unit test to a Python Flask app using Pytest
2 How to set up a REST API in Flask in 5 steps
3 How to generate a TypeScript client from a Swagger documented API
4 How to add type annotations to SQLAlchemy models
Are we all agree that we need to add some tests to our apps, right? In this small post, I’ll show you how to add test to a pretty basic Flask app using Pytest. BONUS: I’ll show you how to add Github Actions CI to your repo.
Let’s say we have a simple “hello world” response in our /
route, just like:
<span>from</span> <span>flask</span> <span>import</span> <span>Flask</span><span>,</span> <span>jsonify</span><span>app</span> <span>=</span> <span>Flask</span><span>(</span><span>__name__</span><span>)</span><span>@</span><span>app</span><span>.</span><span>route</span><span>(</span><span>'/'</span><span>)</span><span>def</span> <span>index</span><span>():</span><span>return</span> <span>jsonify</span><span>({</span><span>'hello'</span><span>:</span> <span>'world'</span><span>})</span><span>if</span> <span>__name__</span> <span>==</span> <span>'__main__'</span><span>:</span><span>app</span><span>.</span><span>run</span><span>(</span><span>debug</span><span>=</span><span>True</span><span>)</span><span>from</span> <span>flask</span> <span>import</span> <span>Flask</span><span>,</span> <span>jsonify</span> <span>app</span> <span>=</span> <span>Flask</span><span>(</span><span>__name__</span><span>)</span> <span>@</span><span>app</span><span>.</span><span>route</span><span>(</span><span>'/'</span><span>)</span> <span>def</span> <span>index</span><span>():</span> <span>return</span> <span>jsonify</span><span>({</span><span>'hello'</span><span>:</span> <span>'world'</span><span>})</span> <span>if</span> <span>__name__</span> <span>==</span> <span>'__main__'</span><span>:</span> <span>app</span><span>.</span><span>run</span><span>(</span><span>debug</span><span>=</span><span>True</span><span>)</span>from flask import Flask, jsonify app = Flask(__name__) @app.route('/') def index(): return jsonify({'hello': 'world'}) if __name__ == '__main__': app.run(debug=True)
Enter fullscreen mode Exit fullscreen mode
So let’s begin by creating a tests
directory and there the conftest.py
file:
<span>import</span> <span>pytest</span><span>from</span> <span>app</span> <span>import</span> <span>app</span> <span>as</span> <span>flask_app</span><span>@</span><span>pytest</span><span>.</span><span>fixture</span><span>def</span> <span>app</span><span>():</span><span>yield</span> <span>flask_app</span><span>@</span><span>pytest</span><span>.</span><span>fixture</span><span>def</span> <span>client</span><span>(</span><span>app</span><span>):</span><span>return</span> <span>app</span><span>.</span><span>test_client</span><span>()</span><span>import</span> <span>pytest</span> <span>from</span> <span>app</span> <span>import</span> <span>app</span> <span>as</span> <span>flask_app</span> <span>@</span><span>pytest</span><span>.</span><span>fixture</span> <span>def</span> <span>app</span><span>():</span> <span>yield</span> <span>flask_app</span> <span>@</span><span>pytest</span><span>.</span><span>fixture</span> <span>def</span> <span>client</span><span>(</span><span>app</span><span>):</span> <span>return</span> <span>app</span><span>.</span><span>test_client</span><span>()</span>import pytest from app import app as flask_app @pytest.fixture def app(): yield flask_app @pytest.fixture def client(app): return app.test_client()
Enter fullscreen mode Exit fullscreen mode
This file will initialize our Flask app and all fixtures you need.
Now, pytest will discover all your test files, let’s create some test files with test_
prefix in the same directory. In this case I’ll test that the route responds with my hello world dict.
<span>import</span> <span>json</span><span>def</span> <span>test_index</span><span>(</span><span>app</span><span>,</span> <span>client</span><span>):</span><span>res</span> <span>=</span> <span>client</span><span>.</span><span>get</span><span>(</span><span>'/'</span><span>)</span><span>assert</span> <span>res</span><span>.</span><span>status_code</span> <span>==</span> <span>200</span><span>expected</span> <span>=</span> <span>{</span><span>'hello'</span><span>:</span> <span>'world'</span><span>}</span><span>assert</span> <span>expected</span> <span>==</span> <span>json</span><span>.</span><span>loads</span><span>(</span><span>res</span><span>.</span><span>get_data</span><span>(</span><span>as_text</span><span>=</span><span>True</span><span>))</span><span>import</span> <span>json</span> <span>def</span> <span>test_index</span><span>(</span><span>app</span><span>,</span> <span>client</span><span>):</span> <span>res</span> <span>=</span> <span>client</span><span>.</span><span>get</span><span>(</span><span>'/'</span><span>)</span> <span>assert</span> <span>res</span><span>.</span><span>status_code</span> <span>==</span> <span>200</span> <span>expected</span> <span>=</span> <span>{</span><span>'hello'</span><span>:</span> <span>'world'</span><span>}</span> <span>assert</span> <span>expected</span> <span>==</span> <span>json</span><span>.</span><span>loads</span><span>(</span><span>res</span><span>.</span><span>get_data</span><span>(</span><span>as_text</span><span>=</span><span>True</span><span>))</span>import json def test_index(app, client): res = client.get('/') assert res.status_code == 200 expected = {'hello': 'world'} assert expected == json.loads(res.get_data(as_text=True))
Enter fullscreen mode Exit fullscreen mode
And that’s it. Now you can run the tests with this line:
python <span>-m</span> pytestpython <span>-m</span> pytestpython -m pytest
Enter fullscreen mode Exit fullscreen mode
The reason why the command looks like the above instead of just pytest
is becase we need to add the directory to the current sys.path
.
BONUS
To setup github actions and get your precious badge for your readme file, you just need to add the following tasks to you YAML file
<span>-</span> <span>name</span><span>:</span> <span>Install Dependencies</span><span>run</span><span>:</span> <span>|</span><span>python -m pip install --upgrade pip</span><span>pip install -r requirements.txt</span><span>-</span> <span>name</span><span>:</span> <span>Run Tests</span><span>run</span><span>:</span> <span>|</span><span>python -m pytest</span><span>-</span> <span>name</span><span>:</span> <span>Install Dependencies</span> <span>run</span><span>:</span> <span>|</span> <span>python -m pip install --upgrade pip</span> <span>pip install -r requirements.txt</span> <span>-</span> <span>name</span><span>:</span> <span>Run Tests</span> <span>run</span><span>:</span> <span>|</span> <span>python -m pytest</span>- name: Install Dependencies run: | python -m pip install --upgrade pip pip install -r requirements.txt - name: Run Tests run: | python -m pytest
Enter fullscreen mode Exit fullscreen mode
You can see the complete YAML file in my sample repo if you want to use it as reference for your app:
po5i / flask-mini-tests
Mini example of Flask and Pytest
This is a examle repository for my article.
Setup
Create and activate the virtual environment
virtualenv venv
source venv/bin/activate
Enter fullscreen mode Exit fullscreen mode
Run the server
python app.py
Enter fullscreen mode Exit fullscreen mode
Run the tests
python -m pytest
Enter fullscreen mode Exit fullscreen mode
The server will be up on http://localhost:5000.
Requirements
Python >= 3.6
License
Update: Also crossposted on Globant’s Medium.
Python series (4 Part Series)
1 How to add basic unit test to a Python Flask app using Pytest
2 How to set up a REST API in Flask in 5 steps
3 How to generate a TypeScript client from a Swagger documented API
4 How to add type annotations to SQLAlchemy models
原文链接:How to add basic unit test to a Python Flask app using Pytest
暂无评论内容