一个简单的MOCK实例

前言

手把手教你如何创建一个简约优美的MOCK框架实例~速戳!

创建一个flask项目

我们可以从pycharm编辑器中直接新建一个flask项目,再添加几个后续要用到的文件,结构初始化如下:

1
2
3
4
5
6
7
8
9
10
11
MyFlaskTest
-flaskr #主程序
-mock_tests
-__init__.py
-mock1.py #mock实例文件
-__init__.py
-static
-templates #存储HTML文件
-app.py #程序启动文件
-config.py #配置文件
-extensions.py #扩展类实例化

其中app.py文件已经自动创建好一个实例,但默认配置显得不够高大上。后续如果想为实例分配不同的环境配置和更清晰的控制程序,我们可以引入工厂函数的概念。

工厂函数

概念

使用工厂函数来创建程序实例,需要使用到蓝图。这个工厂函数用个大白话来说,就是封装一个名为create_app()的函数,这个函数返回程序实例app,使用这个函数就可以在任何地方去创建程序实例。另外借助工厂函数,我们还可以扩展加载和初始化配置,使得创建的对象操作可以分离到单独的模块,减少循环依赖的发生。

工厂函数的使用

在工程文件下编辑init.py文件,代码内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# flaskr/__init__.py

from flask import Flask
from config import EnvConfig #引入环境配置
from .mock_tests import mockTest #引入蓝图实例

def create_app(name):
# 实例化app
app = Flask(__name__, template_folder='templates')

# 获取配置
app.config.from_object(EnvConfig[name])

# 注册蓝图,url_prefix使得被注册的路由URL自动带上前缀
app.register_blueprint(mockTest, url_prefix='/mockTest')
return app

工厂函数接受配置名作为参数,返回创建好的程序实例,加载相关配置。工厂函数一般在程序包的构造文件中创建,你也可以在程序包内新建的模块来存放,比如factory.py或是app.py。

扩展实例

为了更好的运用起工厂函数和完成扩展的初始化操作,我们需要在实例化扩展类时传入程序实例。但使用工厂函数时,并没有一个创建好的程序实例可以导入。如果我们把实例化操作放到工厂函数中,那么我们就没有一个全局的扩展对象可以使用,比如表示数据库的db对象。


为了解决这个问题,大部分扩展都提供了一个init_app()方法来支持分离扩展的实例化和初始化操作。现在我们仍然像往常一样初始化扩展类,但是并不传入程序实例。这时扩展类实例化的工作可以集中放到extension.py脚本中。

1
2
3
4
5
6
7
8
9
#MyFlaskTest/extension.py

from flask_bootstrap import Bootstrap
from flask_sqlalchemy import SQLAlchemy
from flask_mail_import Mail

bootstrap = Bootstrap()
db = SQLAlchemy()
mail = Mail()

现在,当我们需要在程序实例中使用扩展对象时,直接从这个extensions模块导入即可。在工厂函数中,我们导入所有扩展对象,并对其调用init_app()方法,传入程序实例完成初始化操作:

1
2
3
4
5
6
7
8
9
10
11
12
# flaskr/__init__.py
......
from .extensions import bootstrap, db, mail

def create_app(name):
......

bootstrap.init_app(app)
db.init_app(app)
mail.init_app(app)

return app

创建蓝图

Blueprint概念

简单来说,Blueprint 是一个存储操作方法的容器,这些操作在这个Blueprint 被注册到一个应用之后就可以被调用,Flask 可以通过Blueprint来组织URL以及处理请求。 Flask使用Blueprint让应用实现模块化,在Flask中,Blueprint具有如下属性:

  • 一个应用可以具有多个Blueprint
  • 可以将一个Blueprint注册到任何一个未使用的URL下比如 “/”、“/sample”或者子域名
  • 在一个应用中,一个模块可以注册多次
  • Blueprint可以单独具有自己的模板、静态文件或者其它的通用操作方法,它并不是必须要实现应用的视图和函数的
  • 在一个应用初始化时,就应该要注册需要使用的Blueprint
  • 一个Blueprint并不是一个完整的应用,它不能独立于应用运行,而必须要注册到某一个应用中。

蓝图的使用

在mock_tests文件下编辑init.py

1
2
3
4
5
6
#mock_tests/__init__.py

from flask import Blueprint

# 创建一个蓝图实例,名字叫mockTest
mockTest = Blueprint('mockTest', __name__)

创建一个mock程序文件

接下来就非常简单了,想要模拟什么接口就写什么。在mock_tests文件下创建编辑mock1.py文件。

1
2
3
4
5
6
7
8
9
10
11
# mock_tests/mock1.py
from flask import render_template #引入HTML模板文件
from . import mockTest #引入mockTest蓝图

@mockTest.route('/') #使用mockTest标记
def hello_world():
return 'Hello World!'

@mockTest.route('/hey/<name>') #使用mockTest标记
def get_name(name=None):
return render_template('hey.html', name=name)

这样就可以统一使用一个蓝图组件下的不同mock文件,使得文件具有相同的属性。

编辑配置文件

本案例配置文件内容比较简单,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#flask/config.py

# 定义测试环境
class TestConfig:
DEBUG = True

# 定义生产环境
class DevConfig:
DEBUG = False


EnvConfig = {
'Test': TestConfig,
'Dev': DevConfig
}

配置文件可以使用自带参数,也可以自定义环境参数,配置灵活简单。之后还可以配合服务部署做环境配置。送上一份配置参数参考:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
{
'DEBUG': False, # 是否开启Debug模式
'TESTING': False, # 是否开启测试模式
'PROPAGATE_EXCEPTIONS': None, # 异常传播(是否在控制台打印LOG) 当Debug或者testing开启后,自动为True
'PRESERVE_CONTEXT_ON_EXCEPTION': None, # 一两句话说不清楚,一般不用它
'SECRET_KEY': None, # 之前遇到过,在启用Session的时候,一定要有它
'PERMANENT_SESSION_LIFETIME': 31, # days , Session的生命周期(天)默认31天
'USE_X_SENDFILE': False, # 是否弃用 x_sendfile
'LOGGER_NAME': None, # 日志记录器的名称
'LOGGER_HANDLER_POLICY': 'always',
'SERVER_NAME': None, # 服务访问域名
'APPLICATION_ROOT': None, # 项目的完整路径
'SESSION_COOKIE_NAME': 'session', # 在cookies中存放session加密字符串的名字
'SESSION_COOKIE_DOMAIN': None, # 在哪个域名下会产生session记录在cookies中
'SESSION_COOKIE_PATH': None, # cookies的路径
'SESSION_COOKIE_HTTPONLY': True, # 控制 cookie 是否应被设置 httponly 的标志,
'SESSION_COOKIE_SECURE': False, # 控制 cookie 是否应被设置安全标志
'SESSION_REFRESH_EACH_REQUEST': True, # 这个标志控制永久会话如何刷新
'MAX_CONTENT_LENGTH': None, # 如果设置为字节数, Flask 会拒绝内容长度大于此值的请求进入,并返回一个 413 状态码
'SEND_FILE_MAX_AGE_DEFAULT': 12, # hours 默认缓存控制的最大期限
'TRAP_BAD_REQUEST_ERRORS': False,
# 如果这个值被设置为 True ,Flask不会执行 HTTP 异常的错误处理,而是像对待其它异常一样,
# 通过异常栈让它冒泡地抛出。这对于需要找出 HTTP 异常源头的可怕调试情形是有用的。
'TRAP_HTTP_EXCEPTIONS': False,
# Werkzeug 处理请求中的特定数据的内部数据结构会抛出同样也是“错误的请求”异常的特殊的 key errors 。
# 同样地,为了保持一致,许多操作可以显式地抛出 BadRequest 异常。
# 因为在调试中,你希望准确地找出异常的原因,这个设置用于在这些情形下调试。
# 如果这个值被设置为 True ,你只会得到常规的回溯。
'EXPLAIN_TEMPLATE_LOADING': False,
'PREFERRED_URL_SCHEME': 'http', # 生成URL的时候如果没有可用的 URL 模式话将使用这个值
'JSON_AS_ASCII': True,
# 默认情况下 Flask 使用 ascii 编码来序列化对象。如果这个值被设置为 False ,
# Flask不会将其编码为 ASCII,并且按原样输出,返回它的 unicode 字符串。
# 比如 jsonfiy 会自动地采用 utf-8 来编码它然后才进行传输。
'JSON_SORT_KEYS': True,
#默认情况下 Flask 按照 JSON 对象的键的顺序来序来序列化它。
# 这样做是为了确保键的顺序不会受到字典的哈希种子的影响,从而返回的值每次都是一致的,不会造成无用的额外 HTTP 缓存。
# 你可以通过修改这个配置的值来覆盖默认的操作。但这是不被推荐的做法因为这个默认的行为可能会给你在性能的代价上带来改善。
'JSONIFY_PRETTYPRINT_REGULAR': True,
'JSONIFY_MIMETYPE': 'application/json',
'TEMPLATES_AUTO_RELOAD': None,
}

修改app.py文件

因为使用到工厂函数,所以需要修改下app.py文件,代码简单直观。

1
2
3
4
5
6
7
8
9
10
# flaskr/app.py
from flaskr import create_app #引入工厂函数
import os

app = create_app(os.getenv('FLASK_ENV') or 'Test') #获取环境配置信息
app.app_context().push() #加载配置


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

启动程序

当使用flask run命令启动程序时,Flask的自动发现程序实例机制还包含另一种行为:flask会自动从环境变量FLASK_APP的值定义的模块中寻找名称为create_app()或make_app()的工厂函数,自动调用工厂函数创建程序实例并运行。本案例我们是将工厂函数放在app.py中调用,所以我们可以直接用python app.py来直接运行程序,如下:

1
2
3
4
5
6
7
8
9
10
(base) E:\MyFlaskTest>python app.py
* Serving Flask app "flaskr" (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: on
* Restarting with stat
* Debugger is active!
* Debugger PIN: 279-000-282
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

结束

到这里就结束了,同学们可以自行调试,按照工作需要自行添加mock内容。搞定了别忘了来给我点个赞哦,比心!




参考文章:

flask官方中文文档

flask实战-个人博客-使用工厂函数创建程序实例

0%