Flask-蓝图、测试与部署

Flask蓝图、测试与部署

      • 蓝图Blueprint
        • 蓝图的使用
        • 以目录的形式定义蓝图
      • 单元测试
        • 断言assert
        • 单元测试
        • Web请求测试
        • 数据库测试
      • 部署
        • 使用Gunicorn
        • Nginx配置

蓝图Blueprint

蓝图:用于实现单个应用的视图、模板、静态文件的集合。蓝图就是模块化处理的类
简单来说,蓝图就是一个存储操作路由映射方法的容器,主要用来实现客户端请求和URL相互关联的功能。 在Flask中,使用蓝图可以帮助我们实现模块化应用的功能

蓝图的使用

1> 创建蓝图对象:

from flask import Blueprint

# Blueprint必须指定两个参数,app_orders表示蓝图的名称,__name__表示蓝图所在模块
app_orders = Blueprint('app_orders', __name__)

2> 使用蓝图注册路由:

@app_orders.route('/get_orders')
def get_orders():
    return 'get orders page'

3> 在程序实例中注册蓝图:

# app.register_blueprint(app_orders)
# url_prefix的作用是给该蓝图下注册的url添加一个统一的前缀
app.register_blueprint(app_orders, url_prefix='/orders')
以目录的形式定义蓝图

目录结构如图:Flask-蓝图、测试与部署_第1张图片
1>main.py文件中创建app对象和注册蓝图:

from flask import Flask
from cart import app_cart

app = Flask(__name__)

# 注册蓝图
app.register_blueprint(app_cart, url_prefix='/cart')

if __name__ == '__main__':
    app.run()

2>cart/__init__.py文件中创建蓝图对象和导入cart/views.py文件中的视图函数:

from flask import Blueprint

# 创建蓝图对象,template_folder和static_folder指定该蓝图下的模板文件夹和静态文件夹
# 注:如果有一个与cart同级的templates目录,那么将优先从该目录中寻找模板文件
app_cart = Blueprint('app_cart', __name__, template_folder='templates', static_folder='static')

# 在__init__.py文件被执行的时候,把视图加载进来,让蓝图与应用程序知道有视图的存在
from .views import get_cart

3>cart/views.py文件中定义视图函数:

from flask import render_template
from . import app_cart

@app_cart.route('/get_cart')
def get_cart():
    return render_template('cart.html')

单元测试

  • Web程序开发的阶段:需求分析、设计阶段、实现阶段、测试阶段
  • 测试的分类
    测试从软件开发过程可以分为:单元测试、集成测试、系统测试等。在众多的测试中,与程序开发人员最密切的就是单元测试,因为单元测试是由开发人员进行的,而其他测试都由专业的测试人员来完成
  • 单元测试就是开发者编写一小段代码,检验目标代码的功能是否符合预期。通常情况下,单元测试主要面向一些功能单一的模块进行。在Web开发过程中,单元测试实际上就是一些“断言”(assert)代码
  • 断言就是判断一个函数或对象的一个方法所产生的结果是否符合你期望的那个结果。 Python中assert断言是声明布尔值为真的判定,如果表达式为假会发生异常。单元测试中,一般使用assert来断言结果
断言assert

assert是Python中的一个关键字,使用方法如下:

def num_div(num1, num2):
    # assert,断言,后面是一个表达式,如果表达式返回真,则断言成功,程序能够继续向下执行;
    # 如果表达式返回假,则断言失败,抛出AssertionError异常,终止程序的继续执行
    assert isinstance(num1, int)
    assert isinstance(num2, int)
    assert num2 != 0
    print(num1/num2)
单元测试
  • 单元测试的基本写法
    import unittest  # 导入单元测试模块
    
    # 定义一个类,继承自unittest.TestCase
    class TestClass(unittest.TestCase):
        # 该方法会首先执行,相当于做测试前的准备工作
        def setUp(self):
            pass
    
        # 该方法会在测试代码执行完后执行,相当于做测试后的扫尾工作
        def tearDown(self):
            pass
    
        # 测试方法,方法名需要以`test_`开头
        def test_app_exists(self):
            pass
    
  • 常用的断言方法
    方法 说明
    assertEqual() 如果两个值相等,则pass
    assertNotEqual() 如果两个值不相等,则pass
    assertTrue() 判断bool值为True,则pass
    assertFalse() 判断bool值为False,则pass
    assertIsNone() 不存在,则pass
    assertIsNotNone() 存在,则pass
    assertIn() 前者在后者里面,则pass
    assertNotIn() 前者不在后者里面,则pass
Web请求测试

待测试代码:

from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/login', methods=['POST'])
def login():
    # 接收参数
    username = request.form.get('username')
    password = request.form.get('password')
    # 校验数据
    if not all([username, password]):
        resp = {'code': 1, 'msg': '数据不完整'}
        return jsonify(resp)
    if username == 'admin' and password == 'python':
        resp = {'code': 0, 'msg': '登录成功'}
        return jsonify(resp)
    else:
        resp = {'code': 2, 'msg': '用户名或密码不正确'}
        return jsonify(resp)

if __name__ == '__main__':
    app.run(debug=True)

测试代码:

import unittest
from login import app
import json

class LoginTest(unittest.TestCase):
    """构造单元测试案例"""
    def setUp(self):
        """在进行测试之前,先被执行"""
        # 设置测试模式,测试模式打开时,待测试代码出现异常时会抛出异常信息
        # app.config['TESTING'] = True
        app.testing = True
        # 使用Flask的app对象创建Web请求的客户端
        self.client = app.test_client()

    def test_empty_username_password(self):
        """测试用户名或密码不完整的情况"""
        # 使用客户端模拟发送Web请求,data为携带的数据
        response = self.client.post('/login', data={})
        # response是对应视图函数返回的响应对象,data属性是响应体中的数据
        json_data = response.data
        # 将返回的json字符串转换为字典
        resp = json.loads(json_data)
        # 获取返回值后进行断言测试
        self.assertIn('code', resp, '返回数据格式不正确')
        self.assertEqual(resp['code'], 1, '返回状态码不正确')

if __name__ == '__main__':
    unittest.main()  # 启动测试
数据库测试
import unittest
from author_book import Author, app, db

class DatabaseTest(unittest.TestCase):
    def setUp(self):
        app.testing = True
        app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:[email protected]:3306/flask_test'
        db.create_all()  # 生成相应的表格

    def test_add_author(self):
        """测试添加作者到数据库的操作"""
        author = Author(name='zhang')
        db.session.add(author)
        db.session.commit()

        res = Author.query.filter_by(name='zhang').first()
        self.assertIsNotNone(res, '未查询到数据')

    def tearDown(self):
        """在测试结束后执行,通常用来进行扫尾工作"""
        db.session.remove()  # 断开和数据库之间的连接
        db.drop_all()  # 清除所有数据

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

部署

采用Gunicorn做wsgi容器,来部署flask程序。Gunicorn(绿色独角兽)是一个Python WSGI的HTTP服务器。从Ruby的独角兽(Unicorn )项目移植。该Gunicorn服务器与各种Web框架兼容,实现非常简单,轻量级的资源消耗。Gunicorn直接用命令启动,不需要编写配置文件,相对uWSGI要容易很多

  • 区分几个概念
    • WSGI:全称是Web Server Gateway Interface(web服务器网关接口),它是一种规范,它是web服务器和web应用程序之间的接口。它的作用就像是桥梁,连接在web服务器和web应用框架之间
    • uwsgi:是一种传输协议,用于定义传输信息的类型
    • uWSGI:是实现了uwsgi协议WSGI的web服务器
使用Gunicorn

web开发中,部署方式大致类似。简单来说,前端代理使用Nginx主要是为了实现分流、转发、负载均衡,以及分担服务器的压力。Nginx部署简单,内存消耗少,成本低

Nginx既可以做正向代理,也可以做反向代理:
正向代理:请求经过代理服务器从局域网发出,然后到达互联网上的服务器。特点:服务端并不知道真正的客户端是谁
反向代理:请求从互联网发出,先进入代理服务器,再转发给局域网内的服务器。特点:客户端并不知道真正的服务端是谁
区别:正向代理的对象是客户端。反向代理的对象是服务端
安装gunicornpip install gunicorn
查看命令行选项gunicorn -h
运行命令

gunicorn -w 4 -b 127.0.0.1:5000 -D --access-logfile ./logs/log main:app
# -w:表示运行的进程数(worker)
# -b:表示绑定的ip地址和端口号(bind)
# -D:表示在后台运行
# --access-logfile:表示记录访问的日志文件
# ./logs/log:表示日志的存储位置
# main:表示运行的Flask文件名称
# app:表示Flask程序的实例名
Nginx配置

nginx命令:

# 启动
sudo /usr/local/nginx/sbin/nginx
# 查看
ps aux | grep nginx
# 停止
sudo /usr/local/nginx/sbin/nginx -s stop
# 重启
sudo /usr/local/nginx/sbin/nginx -s reload

设置配置文件:
打开/usr/local/nginx/conf/nginx.conf文件

upstream flask {
	# 设置gunicorn服务器
	server 10.666.888.999:5000;
	server 10.666.888.999:5001;
}

server {
    # 监听80端口
    listen 80;
    # 本机
    server_name localhost;
    # 默认请求的url
    location / {
        # 将请求转发到gunicorn服务器
        proxy_pass http://flask;
        # 设置请求头,将用户的头信息传递给服务器端
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

你可能感兴趣的:(Web,框架,Flask,python,flask,web,后端,单元测试)