How to add basic unit test to a Python Flask app using Pytest

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> pytest
python <span>-m</span> pytest
python -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

MIT

View on GitHub

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

© 版权声明
THE END
喜欢就支持一下吧
点赞10 分享
Success is a battle between YOU and YOURSELF only.
成功是一场和自己的比赛
评论 抢沙发

请登录后发表评论

    暂无评论内容