Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Разработка веб-приложений с использованием фреймворка Flask. В 2 частях. Ч.2. Учебное пособие.pdf
Скачиваний:
0
Добавлен:
09.08.2026
Размер:
421 Кб
Скачать
☆

# установка зависимостей

RUN pip install -r requirements.txt

# добавление скрипта entrypoint.sh

COPY ./entrypoint.sh /usr/src/app/entrypoint.sh

# добавление приложения

COPY . /usr/src/app

# запуск сервера

CMD ["./entrypoint.sh"]

Обновим права доступа к файлам:

$ chmod +x services/users/entrypoint.sh

Выполним итоговую проверку:

$ docker-compose -f docker-compose-dev.yml up -d –build

Убедимся, что сервис http://DOCKER_MACHINE_IP: 5001/users/ping всё

ещё работает:

{

"message": "pong!",

"status": "success"

}

Обновим файл manage.py:

# services/users/manage.py

from flask.cli import FlaskGroup from project import app, db

cli = FlaskGroup(app)

@cli.command() def recreate_db():

db.drop_all() db.create_all() db.session.commit()

if __name__ == '__main__': cli()

1.4. НАСТРОЙКА ТЕСТОВ

Начнём процесс написания тестов для приложения. Для этого добавим каталог tests в каталог project, а затем создадим следующие файлы во вновь созданном каталоге:

14

1.__init__.py

2.base.py

3.test_config.py

4.test_users.py

Содержимое файлов показано ниже:

__init__.py

# services/users/project/tests/__init__.py

base.py

# services/users/project/tests/base.py from flask_testing import TestCase from project import app, db

class BaseTestCase(TestCase): def create_app(self):

app.config.from_object('project.config.TestingConfig') return app

def setUp(self): db.create_all() db.session.commit()

def tearDown(self): db.session.remove() db.drop_all()

test_config.py

# services/users/project/tests/test_config.py import os

import unittest

from flask import current_app from flask_testing import TestCase

from project import app

class TestDevelopmentConfig(TestCase): def create_app(self):

app.config.from_object('project.config.DevelopmentConfig') return app

def test_app_is_development(self): self.assertTrue(app.config['SECRET_KEY'] == 'secret_key') self.assertFalse(current_app is None)

self.assertTrue( app.config['SQLALCHEMY_DATABASE_URI'] ==

15

os.environ.get('DATABASE_URL')

)

class TestTestingConfig(TestCase): def create_app(self):

app.config.from_object('project.config.TestingConfig') return app

def test_app_is_testing(self): self.assertTrue(app.config['SECRET_KEY'] == 'secret_key') self.assertTrue(app.config['TESTING'])

self.assertFalse( app.config['PRESERVE_CONTEXT_ON_EXCEPTION'])

self.assertTrue( app.config['SQLALCHEMY_DATABASE_URI'] == os.environ.get('DATABASE_TEST_URL')

)

class TestProductionConfig(TestCase): def create_app(self):

app.config.from_object('project.config.ProductionConfig') return app

def test_app_is_production(self): self.assertTrue(app.config['SECRET_KEY'] == 'secret_key') self.assertFalse(app.config['TESTING'])

if __name__ == '__main__': unittest.main()

test_users.py

# services/users/project/tests/test_users.py import json

import unittest

from project.tests.base import BaseTestCase

class TestUserService(BaseTestCase):

""" Тесты для службы User.""" def test_users(self):

""" Проверка, что маршрут /ping работает корректно.""" response = self.client.get('/users/ping')

data = json.loads(response.data.decode()) self.assertEqual(response.status_code, 200) self.assertIn('pong!', data['message']) self.assertIn('success', data['status'])

16

if __name__ == '__main__':

unittest.main()

Добавим пакет Flask-Testing в файл с требованиями:

Flask-Testing==0.6.2

Добавим новую команду в manage.py для обнаружения и запуска тестов:

@cli.command() def test():

""" Запускает тесты без покрытия кода"""

tests = unittest.TestLoader().discover('project/tests', \ pattern='test*.py')

result = unittest.TextTestRunner(verbosity=2).run(tests) if result.wasSuccessful():

return 0 return 1

Далее импортируем библиотеку unittest:

import unittest

Нам нужно пересобрать образы, поскольку пакеты из файлов с требова-

ниями устанавливаются во время сборки, а не во время выполнения:

$ docker-compose -f docker-compose-dev.yml up -d –build

После запуска контейнеров необходимо запустить тесты:

$ docker-compose -f docker-compose-dev.yml \ run users python manage.py test

После запуска тестов должно появиться следующее сообщение об ошибке:

self.assertTrue(app.config['SECRET_KEY'] == 'secret_key')

Обновим базовую конфигурацию:

class BaseConfig:

"""Базовая конфигурация"""

TESTING = False

SQLALCHEMY_TRACK_MODIFICATIONS = False

SECRET_KEY = 'secret_key'

И проверим результаты выполнения тестов:

------------------------------------------------------------------

Ran 4 tests in 0.071s

OK

1.5.РЕФАКТОРИНГ ПРИЛОЖЕНИЯ

СИСПОЛЬЗОВАНИЕМ FLASK BLUEPRINT

Имея написанные тесты, выполним рефакторинг приложения, добавив в

него концепцию Blueprint.

17

Создадим новый каталог в project с имненм api и добавим файлы

__init__.py, users.py и models.py. Затем в users.py добавим следующий код:

# services/users/project/api/users.py users_blueprint = Blueprint('users', __name__)

@users_blueprint.route('/users/ping', methods=['GET']) def ping_pong():

return jsonify({ 'status': 'success', 'message': 'pong!'

})

Мы создали новый экземпляр класса Blueprint и связали с ним функцию ping_pong(). Затем добавим в models.py следующий код:

# services/users/project/api/models.py class User(db.Model):

__tablename__ = "users"

id = db.Column(db.Integer, primary_key=True, autoincrement=True) username = db.Column(db.String(128), nullable=False)

email = db.Column(db.String(128), nullable=False)

active = db.Column(db.Boolean(), default=True, nullable=False)

def __init__(self, username, email): self.username = username self.email = email

Обновим файл project/__init__.py, удалив маршрут и модель и добавив

шаблон фабрики приложений:

#services/users/project/__init__.py import os

from flask import Flask, jsonify

from flask_sqlalchemy import SQLAlchemy

#инстанционирование базы данных

db = SQLAlchemy()

def create_app(script_info=None):

# инстанционирование приложения app = Flask(__name__)

# подключение конфигурации app_settings = os.getenv('APP_SETTINGS') app.config.from_object(app_settings)

#запуск расширений db.init_app(app)

18

# регистрация blueprints

from project.api.users import users_blueprint app.register_blueprint(users_blueprint)

# контекст оболочки для flask cli app.shell_context_processor({'app': app, 'db': db}) return app

Обратите внимание на shell_context_processor. Этот механизм использу-

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

средственно в оболочку.

Обновим файл manage.py:

# services/users/manage.py import unittest

from flask.cli import FlaskGroup

from project import create_app, db from project.api.models import User

app = create_app()

cli = FlaskGroup(create_app=create_app)

@cli.command() def recreate_db():

db.drop_all() db.create_all() db.session.commit()

@cli.command() def test():

"""Запускает тесты без покрытия кода"""

tests = unittest.TestLoader().discover('project/tests',\ pattern='test*.py')

result = unittest.TextTestRunner(verbosity=2).run(tests) if result.wasSuccessful():

return 0 return 1

if __name__ == '__main__': cli()

Обновим содержание части импорта в заголовке файлов project/tests/

base.py и project/tests/test_config.py:

19

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]