Рубрики
Без рубрики

Построение Restful API с помощью Flask, Postman & PyTest – Часть 3 (Время чтения: 20 Минут)

Сегодня в нашей заключительной части серии из 3 частей я расскажу о создании реальных REST API с помощью PyTest.

Автор оригинала: Max Ong Zong Bao.

Сегодня в нашей заключительной части серии из 3 частей я расскажу о создании реальных REST API с помощью PyTest.

Для тех, кто новичок в этой серии, вы можете посмотреть на часть 1 , чтобы понять различные инструменты, которые я буду использовать для создания конечных точек REST API менеджера расходов.

Кроме того, посмотрите на часть 2 в издевательстве над конечными точками API для прототипирования ваших проектов API.

Инструмент

исходный код

Конечные Точки Для Создания

Теперь в последней части серии мы рассмотрим функции CRUD , которые используют только метод HTTP-запроса GET .

Поскольку создание PUT , POST и DELETE конечных точек идентично, было бы лучше ввести использование Pytest .

Конечные точки и документация API Заключительная часть:

Документация API в Postman

  • Получить список транзакций – GET
  • Создать новую транзакцию – POST
  • Обновление отдельной транзакции – PUT
  • Удалить отдельную транзакцию – УДАЛИТЬ

Настройка проекта

Создание папки проекта

Создайте свой проект в Linux , создав папку с именем expenses_manager .

Далее в разделе создайте виртуальную среду с помощью pipe и переключитесь на виртуальную среду python.

pipenv install
pipenv shell

Установка пакетов Python

Теперь вам нужно установить следующее, набрав команду ниже.

pipenv shell
pipenv install Flask flask-cors pytest pytest-cov pytest-flask requests pylint

Установив базовые пакеты python, мы приступим к созданию нашего первого приложения Flask.

Создание Вашего Первого приложения Flask

Создайте файл с именем expenses_manager.py , затем откройте IDE или выбранный редактор, чтобы внести изменения в содержимое файла.

Создайте файл с именем || expenses_manager.py || , затем откройте IDE или выбранный редактор, чтобы внести изменения в содержимое файла.

from flask import Flask # Import the flask web server
app = Flask( __name__ ) # Single module that grabs all modules executing from this file

@app.route('/') # Tells the flask server on which url path does it trigger which for this example is the index page calling "hello_world" function.
def hello_world():
    return 'Hello, World!'

Выполнение приложения Flask

Теперь, как только вы добавили код в файл, нам нужно выполнить следующую команду start this flask app:

export FLASK_APP=expenses_manager.py
flask run

Поздравляю вы только что создали свое первое приложение flask. Вы можете открыть свой браузер и ввести в него следующий URL-адрес “127.0.0.1:5000”. Для отмены вам нужно нажать ctrl + c , чтобы выйти из сервера.

счастливый giphy

Режим Разработки В Колбе

Введите следующую команду, чтобы мы включили режим development .

В этом режиме ваше приложение flask имеет отладчик и автоматически перезапускается самостоятельно всякий раз, когда происходит изменение кода.

export FLASK_ENV=development
flask run

Понимание маршрутизации

Маршрутизация-это способ, которым вы назначаете определенную веб-страницу для загрузки. Это может быть простой пример, как показано ниже:

@app.route('/') # Routes you to the index page
def index():
    return 'Index Page'

@app.route('/hello') # Routes you to the page with http://127.0.0.1:5000/hello/
def hello():
    return 'Hello, World'

@app.route('/projects/') # URL with trailing slash
def projects():
    return 'The project page'

@app.route('/about') # URL without a trailing slash
def about():
    return 'The about page'

Это может быть очень просто или очень сложно, я не буду много рассказывать, так как мы сосредоточены на построении функции GET менеджера расходов .

Я прикреплю справочную ссылку для вас к разделу ссылок для лучшего понимания маршрутизации.

Обратите внимание, что по умолчанию если вы не включаете URL-адрес с завершающей косой чертой , который является этим / .

Колба будет автоматически перенаправлять вас 404 когда вы добавляете страницу с / в конце URL-адреса.

Создание Первой Конечной Точки REST API

Если вы не читали более ранние части серии, пожалуйста, перейдите к части 2 или 3 серии, чтобы понять, что такое HTTP-методы и код состояния .

Вы можете посмотреть на приведенный ниже пример, изменив свой expenses_manager.py код к следующему, чтобы понять, как это работает.

from flask import Flask, request, jsonify # Imports the flask library modules
app = Flask( __name__ ) # Single module that grabs all modules executing from this file

@app.route('/login', methods=['GET', 'POST']) # HTTP request methods namely "GET" or "POST"
def login():
    data = []
    if request.method == 'POST': # Checks if it's a POST request
        data = [dict(id='1', name='max', email='max@gmail.com')] # Data structure of JSON format
        response = jsonify(data) # Converts your data strcuture into JSON format
        response.status_code = 202 # Provides a response status code of 202 which is "Accepted" 

        return response # Returns the HTTP response
    else:
        data = [dict(id='none', name='none', enmail='none')] # Data structure of JSON format
        response = jsonify(data) # Converts your data strcuture into JSON format
        response.status_code = 406 # Provides a response status code of 406 which is "Not Acceptable"

        return response # Returns the HTTP response

Теперь вы можете открыть свой Postman , чтобы создать запрос под названием Testing Login Request .

Введите этот URL-адрес http://127.0.0.1:5000/login чтобы ваш запрос и setHTTPmethod были либо GET , либо POST request, затем нажмите send , чтобы получить результат ответа.

mic drop giphy

Создание скрипта Bash для настройки параметров конфигурации

Мы создадим скрипт bash , который позволит выполнять вышеперечисленные настройки без постоянного ввода команды.

Создайте файл, который называется env.sh и заполните содержимое файла приведенным ниже кодом.

Создайте файл, который называется || env.sh || и заполните содержимое файла приведенным ниже кодом.

#!/usr/bin/env bash
pipenv shell
export FLASK_ENV=development FLASK_APP=expenses_manager.py
flask run

После того, как вы создали файл с именем env.sh , вам нужно изменить разрешение файла с помощью этой команды:

Чтобы запустить скрипт bash, вам нужно находиться в папке project root , используя приведенную ниже команду.

Создание вашего первого тестового случая

Теперь мы начнем с создания нашего первого тестового случая для вашей конечной точки flask API.

Мы проверим, работает ли приложение flask, проверив, служит ли index.page HTTP-ответом.

Создание test_endpoints.py

Итак, давайте создадим тестовый скрипт вызова test_endpoints.py и добавьте следующий код в только что созданный файл:

Итак, давайте создадим тестовый скрипт вызова || test_endpoints.py || и добавьте следующий код в только что созданный файл:

import pytest
import requests

url = 'http://127.0.0.1:5000' # The root url of the flask app

def test_index_page():
    r = requests.get(url+'/') # Assumses that it has a path of "/"
    assert r.status_code == 200 # Assumes that it will return a 200 response

Выполнение test_endpoints.py

Пусть приложение flask работает в первом терминале. Затем создайте второй терминал и запустите pytest , используя приведенную ниже команду:

грустный гифи
pytest1

Вы видели F рядом с вашим test_endpoints.py это означает, что ваш тестовый случай провалился .

Пожалуйста, не беспокойтесь, так как это ожидаемое поведение с нашей первой попытки, так как мы не включили конечную точку индекса , которая возвращает ответ .

Чтобы исправить свой тестовый сценарий, вы можете следовать предложению pytest, изменив код состояния на 400 вместо этого 200 и выполните тест еще раз.

Тест действительно проходит с “.” но это не сможет проверить , если ваше приложение flask работает под корневой папкой и возвращает HTTP 200 ответ.

Поэтому нам нужно создать конечную точку индекса вместо того, чтобы исправлять наши тестовые случаи.

Создайте конечную точку индекса

Поскольку тестовый случай в test_index_page требует конечной точки с путем /| и HTTP-ответом 200 .

Мы добавим индексную страницу в наш expenses_manager.py :

Мы добавим индексную страницу в наш || expenses_manager.py ||:

@app.route('/', methods=['GET'])
def index_page():
    response = jsonify('Hello World!!!')
    response.status_code = 200
    
    return response

Теперь введите pytest -v в 2-й терминал в то время как ваш 1-й терминал выполняет приложение flask.

Команда pytest-v предоставляет вам дополнительную информацию о ваших тестовых случаях, которая также полезна для отладки ваших тестовых случаев и конечных точек python.

Теперь после выполнения предыдущей команды вы должны увидеть, что ваши тестовые случаи проходят. Потрясающая работа!!!! При создании вашей первой конечной точки и тестового случая.

Давайте сделаем заслуженный отдых и перейдем к следующему разделу, когда вы будете готовы погрузиться дальше.

pytest2
счастливый giphy

Создание конечных точек Менеджера расходов

С тех пор как вы начали создавать свою первую конечную точку в Flask & test cases с помощью Pytest .

Давайте рассмотрим, как составляется список API, необходимых для создания менеджера расходов:

Список API для создания:

  • Получить список транзакций – GET
  • Создать новую транзакцию – POST
  • Обновление отдельной транзакции – PUT
  • Удалить отдельную транзакцию – УДАЛИТЬ

Получить список транзакций

Теперь начните с первой конечной точки GET , которая предоставляет список транзакций.

Что такое минимальный тест , который нам нужно создать, чтобы проверить, работает ли он?

Создание Пользовательских Историй

истории о foo fighters

Пользовательские истории полезны для того, чтобы выяснить, что нужно создать перед реализацией.

Мы возьмем этот сценарий user story script для создания пользовательского тестового случая:

As (role of the user), I want to (the activity) so that (desired result)

Таким образом, при создании пользовательской истории это будет выглядеть примерно так

Как Пользователь , я хочу иметь снимок моих расходов , чтобы я знал, куда я трачу свои деньги

Создание Тестового случая для Баланса В Менеджере расходов

С помощью этой пользовательской истории мы можем построить минимальный тестовый случай. Который должен показать баланс , который у нас есть на вашем счете.

С помощью этой || пользовательской истории || мы можем построить минимальный тестовый случай. Который должен показать || баланс||, который у нас есть на вашем счете.

def test_get_balance_in_transacations():
    r = requests.get(url+'/transactions/')
    
    assert r.status_code == 200

Теперь давайте запустим ваш недавно созданный test_get_balance_in_transactions тестовый случай.

Поскольку вы не создали конечную точку transactions , она не может попросить вас изменить тестовый случай на 404 .

Чтобы он прошел, нам нужно вызвать конечную точку под названием transactions in expenses_manager.py .

Чтобы он прошел, нам нужно вызвать конечную точку под названием || transactions || in || expenses_manager.py || .

@app.route('/transactions/', methods=['GET'])
def list_of_transactions():
    response = jsonify({})
    response.status_code = 200
    return response

С этим вы должны были пройти свое первое испытание. Теперь давайте создадим еще один тестовый случай, который проверяет содержимое ответа на наличие баланса 0 .

С этим вы должны были пройти свое первое испытание. Теперь давайте создадим еще один тестовый случай, который проверяет содержимое ответа на наличие || баланса |||| 0 || .

def test_get_balance_in_transacations():
    r = requests.get(url+'/transactions/')
    assert r.status_code == 200
    
    data = r.json()
    assert data[balance'] == 0

Ожидайте, что ваши тестовые случаи потерпят неудачу, если вы запустите приведенный выше код. Нам нужно изменить expenses_manager.py чтобы это прошло.

Ожидайте, что ваши тестовые случаи потерпят неудачу, если вы запустите приведенный выше код. Нам нужно изменить || expenses_manager.py || чтобы это прошло.

@app.route('/transactions/', methods=['GET'])
def list_of_transactions():
    response = jsonify({'balance': 0})
    response.status_code = 200
    return response

Когда вы запустите его снова, вы увидите, что он проходит для этого тестового случая.

Вы завершили Историю пользователя?

Итак, теперь мой вопрос к вам: выполнили ли мы нашу историю пользователя для этого тестового случая?

Если нет, то чего еще не хватает? Хорошей догадкой будут фиктивные конечные точки, которые вы создали в part 2 .

Поскольку мы знаем, что помимо баланса менеджера расходов, нам нужно получить количество транзакций , основанных в конечной точке.

Перед этим нам нужно очистить наш код для этой test_get_balance_in_transactions конечной точки.

Перед этим нам нужно очистить наш код для этой || test_get_balance_in_transactions || конечной точки.

def test_get_balance_in_transacations():
    r = requests.get(url+'/transactions/')
    data = r.json()
    
    assert r.status_code == 200
    assert data['balance'] == 0

Получить количество транзакций в конечной точке Транзакций

Как только вы закончите с этим кодом, создайте новый тестовый случай, который проверяет количество транзакций в конечной точке Transactions .

Как только вы закончите с этим кодом, создайте новый тестовый случай, который проверяет количество транзакций в конечной точке || Transactions||.

def test_get_number_of_transacations():
    r = requests.get(url+'/transactions/')
    data = r.json()
    
    assert r.status_code == 200
    assert len(data['transactions']) != 0

Этот тестовый случай проверяет общее количество транзакций должно быть больше, чем 0 .

В очередной раз ваш тестовый случай | терпит неудачу поэтому давайте создадим транзакцию для тестового случая, чтобы пройти .

В очередной раз ваш || тестовый случай || | терпит неудачу || поэтому давайте создадим транзакцию для тестового случая, чтобы || пройти || .

@app.route('/transactions/', methods=['GET'])
def list_of_transactions():
    response = jsonify({'balance': 0, 
    'transactions': [ 
        {}
    ]})
    response.status_code = 200
    return response

Проверка полей отдельной транзакции

проверка книг efteling

Как и вы до сих пор, мы только проверили, имеет ли он больше, чем 0 сделки.

Мы не смогли проверить, имеют ли транзакции те же поля, что и фиктивные конечные точки , найденные в части 2 серии.

Итак, теперь давайте создадим эти тесты для проверки полей внутри транзакций.

Итак, теперь давайте создадим эти тесты для проверки полей внутри транзакций.

def test_individual_transaction_fields():
    r = requests.get(url+'/transactions/')
    data = r.json()
    fields = list(data['transactions'])

    assert r.status_code == 200
    assert fields[0]['amount'] >= 0.00
    assert fields[0]['current_balance'] < 240
    assert 'jean' in fields[0]['description']
    assert 0 < fields[0]['id'] 
    assert 300 == fields[0]['inital_balance'] 
    assert "2019-01-12 09:00:00" == fields[0]['time']
    assert fields[0]['type'] != 'income'

Опять же, когда вы запускаете это изначально, это не удается, так что теперь самое время добавить в поля отдельные транзакции.

Опять же, когда вы запускаете это изначально, это не удается, так что теперь самое время добавить в поля отдельные транзакции.

@app.route('/transactions/', methods=['GET'])
def list_of_transactions():
    response = jsonify({'balance': 0, 
    'transactions': [ 
        {'amount': 0.0, 'current_balance': 230, 'description': 'blue jean', 'id':2, 'inital_balance': 300, 'time': "2019-01-12 09:00:00", 'type': 'expense'}
    ]})
    response.status_code = 200
    return response

Рефакторинг В Один Класс

Теперь мы проведем рефакторинг вашего 4 тестовые случаи и консолидировать его в один класс для удобства выполнения тестов, которые мы называем test suite .

Который вы можете ввести эту команду для тестирования этого конкретного набора тестов

pytest -v test_endpoints.py::NameOfTheSuite

Который вы можете ввести эту команду для тестирования этого конкретного набора тестов ||

class TestTransactions():
    def test_index_page(self):
        r = requests.get(url+'/')
        assert r.status_code == 200

    def test_get_balance_in_transacations(self):
        r = requests.get(url+'/transactions/')
        data = r.json()

        assert r.status_code == 200
        assert data['balance'] == 0

    def test_get_number_of_transacations(self):
        r = requests.get(url+'/transactions/')
        data = r.json()

        assert r.status_code == 200
        assert len(data['transactions']) != 0

    def test_individual_transaction_fields(self):
        r = requests.get(url+'/transactions/')
        data = r.json()
        fields = list(data['transactions'])

        assert r.status_code == 200
        assert fields[0]['amount'] >= 0.00
        assert fields[0]['current_balance'] < 240
        assert 'jean' in fields[0]['description']
        assert 0 < fields[0]['id'] 
        assert 300 == fields[0]['inital_balance'] 
        assert "2019-01-12 09:00:00" == fields[0]['time']
        assert fields[0]['type'] != 'income'

Основы тестовой разработки

Если вы не заметили, что постоянный сбой и рефакторинг для прохождения ваших тестовых случаев-это практика разработки программного обеспечения, называемая Test Driven Development .

практика делает совершенным

Который может быть использован в дополнение к нему с помощью Pytest для создания различных тестовых случаев для ваших будущих проектов.

Основной процесс TDD

  • Создайте неудачный тестовый случай
  • Реализовать код передать
  • Рефакторинг кода и снова начните с самого верха

Оставшиеся истории конечных точек

Вот оставшиеся конечные точки пользовательские истории для вас, чтобы создать которые я предоставлю исходный код через две недели в моем репо GitHub для этой сопутствующей серии учебников:

Создайте новую транзакцию – Как Пользователь , я хочу иметь запись моих расходов так, чтобы Я знал, куда идут мои деньги

Обновить отдельную транзакцию – Как Пользователь , я хочу отредактировать конкретную транзакцию так, чтобы ** У меня был правильный баланс**

Удалить отдельную транзакцию – Как Пользователь , я хочу удалить транзакцию так, чтобы ** У меня был правильный баланс в моем менеджере расходов**

Вывод

Если бы вы были со мной до самого конца этой серии, я хотел бы поблагодарить вас за то, что вы нашли время, чтобы пройти через эту серию из 3 частей, поскольку написать ее-это не просто подвиг.

Помните, что я выпущу решение для этой серии оставшихся конечных точек для POST , PUT & DELETE HTTP-запросов примерно через две недели .

Для меня было честью написать это 3 часть серии, я надеюсь, что то, что вы узнали, может быть полезно вам в создании RESTful API конечных точек в Flask с использованием PyTest , Postman и TDD методов.

Если вам понравилась моя статья, пожалуйста подпишитесь на рассылку Max Adventurer’s Newsletter для потрясающего контента, на который я натыкаюсь еженедельно в Python , Startup и Web Development .

Вы также можете следовать за мной, чтобы получить последнее обновление моей статьи о CodeMentor

Этот пост был первоначально опубликован в блоге Макса по адресу Building Restful API with Flask, Postman & PyTest – Part 3 (Время чтения: 20 минут) и фото из Фото Рейчел Горжестани на Unsplash

Менеджер Расходов Исходный Код

Документация API В Postman

Написание Тестовых Случаев Формирует Пользовательские Истории Из Критериев Принятия

История пользователя

Разработка на основе тестов: что это такое, а что нет.

Тестирование Python С Помощью Pytest

Колба

PyTest

Метод HTTP-запроса

Коды состояния HTTP