Python(七) —— mock接口开发
mock接口开发
接口开发有很多框架,诸如 Django,flask,相比较而言,flask 是轻量级web开发框架,用来开发 mock 接口的不二之选。那你可能会问,什么叫 mock 接口呢?mock 的意思是模拟。
mock 接口的使用场景
场景1
假定在做接口测试,你正在编写自动化脚本,但是依赖于另一个接口的返回数据,但是另一个接口有问题/未开发完成,那么就需要构造接口的数据。这时候,我们可以利用 mock 接口的方式,构造出一个接口来造出我们需要的返回数据。从而不因为其他模块而阻碍当前进度。
场景2
假设公司内部部门不同,部门之间有交互,交互的话,假设别人想要我的订单表数据,但是我不想把数据库暴露给别人,那可以开发一个 mock 接口,这样他们可以通过这个接口访问数据库,但是却不知道数据库的进入方式以及数据库形式。
接下来我们就利用 flask 来构造 mock 接口,其中包括 get 请求,post 的 key-value 形式,json 形式,上传文件,访问数据库等
模板
首先安装好 flask 模块:pip install Flask ,其次开始写接口,接口是有模板的,具体如下:
import flask,json server = flask.Flask(__name__) @server.route('/login')
def welcome():
data = {'code':0,'msg':'ganziwen登陆成功','session_id':'sdf234sdsdfsdfs'}
return json.dumps(data,ensure_ascii=False) server.run(host='0.0.0.0',port=8888,debug=True) #
我们对其进行解读:
- server=flask.Flask(__name__) # 这个可以理解为固定写法,意思是起一个 flask 的服务
- @server.route('/login') # 这是个装饰器,代表下面的函数不是个普通的函数,而是一个接口,/login 是接口路径,跟下面的函数名不一定要一致,假设设置为 /,那么就是代表该接口下的默认接口
- def welcome(): # 这个是接口内的函数,要跟上一行紧挨着,且函数名不能有重复的
- return 是返回什么玩意,这里我们返回 json 串。假设要更好看点,可以在后面加:indent = 4,这样格式化起来更好看
- server.run(host='0.0.0.0',port=8888,debug=True) # 这个是代表启动接口的服务,host 可以为 127.0.0.1,这样只能本机访问,如果想要局域网内的用户都能访问,那么设置成 0.0.0.0 ,port 代表启动服务的端口,默认是 5000 ,debug=True 代表自动调试,假设改了接口代码,不用重新运行,以免忘记去重新运行启动服务
- 运行该服务,编译期内看到 * Running on http://0.0.0.0:8888/ (Press CTRL+C to quit) ;且在浏览器内访问 127.0.0.1:8888/login 查看到是我们定义的结果如下
{
code: 0,
msg: "ganziwen登陆成功",
session_id: "sdf234sdsdfsdfs"
}
get请求
1、获取请求参数
其实上面的接口就是个 get 接口的形式,但是是相对而言比较简单的,那么我们的接口当中,get 请求有的也是要加参数的,比如说 ?username=xxxpasswd=xxx 那么怎么办呢?
@server.route('/urldata') #get请求,参数在url里面的
def urlData():
u = flask.request.args.get('username')
p = flask.request.args.get('password')
data = {'username':u,'password':p}
return json.dumps(data,ensure_ascii=False)
flask.request.args.get('key') # 这个就是接口内需要传的参数 key,前面用变量获取
这时候,访问对应的地址就应该加上这两个参数,比如:http://127.0.0.1:8888/urldata?username=123&password=456
结果
{
username: "",
password: ""
}
可以明显的看到,传的参数,显示在结果内,我们的函数要实现的功能也是如此
假设要传的参数未传,那么参数获取到的值就是 None,反映在结果内就是 Null
post请求
和 get 形式的有些许不同,在 meythods 内指定 = ['post'],默认是 get 形式的
1、form-data 形式
@server.route('/add_student',methods=['post'])
def add_stu(): stu_name = flask.request.values.get('name')
pwd = flask.request.values.get('pwd') return json.dumps({'msg':'添加成功!'},ensure_ascii=False)
flask.request.values.get('key') # 获取 form-data 形式内的参数值
2、json形式
@server.route('/add_student2',methods=['post'])
def add_stu2():
if flask.request.is_json: # 判断 request 的形式是否为 json 形式,如果不加这个判断,传进来为 key-value 形式就会报错 AttributeError
stu_name = flask.request.json.get('name')
pwd = flask.request.json.get('pwd')
#print(flask.request.json) # 可以打印出传进来的所有参数
return json.dumps({'msg':'添加成功!'},ensure_ascii=False)
else:
return json.dumps({'msg':'入参请传入json'},ensure_ascii=False)
3、上传文件
@server.route('/file',methods=['post'])
def uploadFile():
file = flask.request.files.get('f')
print(file.filename) #获取到上传的文件名
#path ='~/Desktop/'+file.filename #保存文件的路径,这个可以写成绝对路径
#file.save(path) # 和上面一行是成对出现,将文件保存到绝对路径
file.save(file.filename) #保存,这样是保存到 python 文件的目录下
# print(dir(file))
return json.dumps({'msg':'上传完成!'},ensure_ascii=False)
这个其实没有规避掉一个问题,文件名重复的怎么办?可以在文件名后面加一个时间戳,这样上传就基本不会有一样的了,这里我们就不写太多
从数据库获取数据
比如说,其他部门想要获取某个库,但是不想把整个数据库暴露给别人,怎么办呢?可以用接口实现,比如说:传一个表就给你返回这个表的数据:/table_data?table_name=xxx&limit=xxx
首先要写好 sql 的执行函数,之前我们写过:
def op_mysql(sql:str):
mysql_info = {
'host': '118.24.3.40',
'port': 3306,
'password': '',
'user': 'jxz',
'db': 'jxz',
'charset': 'utf8',
'autocommit': True
}
result = '执行完成'
conn = pymysql.connect(**mysql_info)
cur = conn.cursor(pymysql.cursors.DictCursor) #建立游标
cur.execute(sql)
if sql.strip().lower().startswith('select'):
# result = cur.fetchone()
result = cur.fetchall()
cur.close()
conn.close()
return result
接口内容:
import flask,json
server = flask.Flask(__name__)
@server.route('/table_data')
def get_table_data():
table = ['app_myuser','dsk_test','app_student']
table_name = flask.request.args.get('table_name')
limit = flask.request.args.get('limit','') #10 为默认值
if not table_name:
return json.dumps({'msg':'table_name是必填字段'},ensure_ascii=False)
if table_name not in table:
return json.dumps({'msg':'没权限访问'},ensure_ascii=False)
if limit.isdigit():
sql = 'select * from %s limit %s;'%(table_name,limit)
else:
return json.dumps({'msg':'limit 请传入整数'},ensure_ascii=False)
res = op_mysql(sql)
return json.dumps(res,ensure_ascii=False) server.run(host='0.0.0.0',port = 5000,debug=True)
这个里面是写好了刚刚的要求,设定的表是可以定义的,不在里面的表访问不了,报没权限;
limit 判断了是否为整数,默认值为 10 ,也可以自己改;
table_name 必须传,没传就会报其是一个必填字段
这个是 get 实现,也可以自己定义为 post 实现
结果如下:
[
{
id: 422,
username: "glw",
passwd: "",
is_admin: 123,
error_count: 0
},
{
id: 424,
username: "glw1",
passwd: "",
is_admin: 123,
error_count: 0
},
……
]
程序分目录
在正常的开发中,不可能像我们之前写的那样,什么都扔在一个文件里面,逻辑,数据,配置全部写在一起的话,难以维护。那么有没有什么框架来维护呢?接下来看一下,一个简单的框架是怎样的
API
|__bin # 执行文件的目录
| |__start.py
|
|__config # 配置文件,数据库,服务器端口,md5 加盐值等
| |__setting.py
|
|__lib # 实现函数
| |__interface.py # 接口实现
| |__tools.py # 小工具:操作 mysql ,加盐等
|
|__logs # 日志文件夹
|
|__readme.txt # 文件以及文件夹内部内容说明
|
|__第三方模块.txt # 整个工程安装运用的第三方模块说明
配置文件路径
在程序分目录的过程中,涉及到一个问题:模块之间的引用,在 windows 的 pycharm 内,可以很快地设置环境变量:在程序的主目录上,例如上述就是在 API 文件夹==>右键==>Mark Directory as ==> Source Root,设置好后,API 文件夹为蓝色,那么这个文件夹下的模块就可以相互引用。而且存在一个问题,假设 API 的同一级目录有一个:API2 也设置了 Source Root ,这样 API2 导入模块也没用,所以说 Source Root 只能有一个。
或者在启动文件内,将文件的路径写进去,这样也可以
那么,你可能会问,那我要把程序放到 Linux 内,没有 pycharm 怎么用?有没有终极解决方案呢?有的!
我们在 bin 的 start.py 里面可以设置,将 API 的路径加入到 python 环境变量内:
import sys
import os
BASE_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0,BASE_PATH)
os.path.abspath(__file__) 代表本文件路径
os.path.dirname() 代表文件的父目录
也就是这里取了两级父目录,取几级视情况而定
实例
为了更好的理解目录分级,我们这里举个例子说明一下目录分级的文件:
启动文件:
import sys
import os
BASE_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0,BASE_PATH) from config.setting import server_info
from lib.interface import server server.run(**server_info)
start.py
配置文件
mysql_info = {
'host': '118.24.3.40', #ip
'port': 3306, #端口号
'password': '', #密码
'user': 'jxz', #用户
'db': 'jxz',#数据库
'charset': 'utf8',
'autocommit': True
} redis_info = {
'host': '118.24.3.40', #ip
'port': 6379, #端口号
'password': 'HK139bc&*', #密码,
'db':0
} SALT = '@#@$#%SD324532sfd' #盐 server_info = {
'port':8888,#端口号
'debug':True,#是否调试模式
'host':'0.0.0.0'
}
setting.py
接口:
import flask,json
from . import tools server = flask.Flask(__name__) @server.route('/table_data')
def get_table_data():
#没有实现校验表是否存在
tables = ['app_myuser','dsk_test','app_student','app_product']
table_name = flask.request.args.get('table_name')
limit = flask.request.args.get('limit','')
if table_name not in tables:
return json.dumps({'msg':'没有获取这个表的权限!'},ensure_ascii=False)
if not table_name:
return json.dumps({'msg':"table_name是必填字段"},ensure_ascii=False)
if limit.isdigit():
sql = 'select * from %s limit %s; '%(table_name,limit)
else:
return json.dumps({'msg':'limit请传入一个整数!'},ensure_ascii=False)
result = tools.op_mysql(sql)
return json.dumps(result,ensure_ascii=False) @server.route('/add_mem',methods=['post'])
def add_mem():
#没有实现校验表是否存在
#qq_mem
username = flask.request.json.get('username')
password = flask.request.json.get('password')
if username and password :
sql='select * from app_myuser where username="%s";'%username
if tools.op_mysql(sql):
data = {'msg':'用户已经存在'}
else:
new_password = tools.md5(password)
insert_sql = 'insert into app_myuser (username,passwd) value ("%s","%s");'%(username,new_password)
data = {'msg':'用户添加成功!'}
tools.op_mysql(insert_sql)
else:
data = {'msg':'必填参数未填,请查看接口文档!'}
return json.dumps(data,ensure_ascii=False)
interface.py
接口实现:
import hashlib,pymysql
from config import setting def md5(s,):
s = (str(s)+setting.SALT).encode()
m = hashlib.md5(s)#加密
return m.hexdigest() def op_mysql(sql:str):
result = '执行完成'
conn = pymysql.connect(**setting.mysql_info)
cur = conn.cursor(pymysql.cursors.DictCursor) #建立游标
cur.execute(sql)
if sql.strip().lower().startswith('select'):
# result = cur.fetchone()
result = cur.fetchall()
cur.close()
conn.close()
return result
tools.py
文件说明:
#这个程序是写xxx接口的 入口文件是main.py config下面是配置文件 lib是程序的主逻辑在这里面 需要安装的第三方模块
flask
pymysql
readme.txt
引用模块
alabaster==0.7.10
anaconda-client==1.6.14
anaconda-navigator==1.8.7
anaconda-project==0.8.2
appnope==0.1.0
appscript==1.0.1
asn1crypto==0.24.0
astroid==1.6.3
astropy==3.0.2
attrs==18.1.0
Babel==2.5.3
backcall==0.1.0
backports.shutil-get-terminal-size==1.0.0
beautifulsoup4==4.6.0
bitarray==0.8.1
bkcharts==0.2
blaze==0.11.3
bleach==2.1.3
bokeh==0.12.16
boto==2.48.0
Bottleneck==1.2.1
certifi==2018.4.16
cffi==1.11.5
chardet==3.0.4
click==6.7
cloudpickle==0.5.3
clyent==1.2.2
colorama==0.3.9
conda==4.6.14
conda-build==3.10.5
conda-verify==2.0.0
contextlib2==0.5.5
cryptography==2.2.2
cycler==0.10.0
Cython==0.28.2
cytoolz==0.9.0.1
dask==0.17.5
datashape==0.5.4
decorator==4.3.0
distributed==1.21.8
Django==2.1.7
docutils==0.14
entrypoints==0.2.3
et-xmlfile==1.0.1
Faker==1.0.2
fastcache==1.0.2
filelock==3.0.4
Flask==1.0.2
Flask-Cors==3.0.4
gevent==1.3.0
glob2==0.6
gmpy2==2.0.8
greenlet==0.4.13
h5py==2.7.1
heapdict==1.0.0
html5lib==1.0.1
idna==2.6
imageio==2.3.0
imagesize==1.0.0
ipykernel==4.8.2
ipython==6.4.0
ipython-genutils==0.2.0
ipywidgets==7.2.1
isort==4.3.4
itsdangerous==0.24
jdcal==1.4
jedi==0.12.0
Jinja2==2.10
jsonpath==0.80
jsonschema==2.6.0
jupyter==1.0.0
jupyter-client==5.2.3
jupyter-console==5.2.0
jupyter-core==4.4.0
jupyterlab==0.32.1
jupyterlab-launcher==0.10.5
kiwisolver==1.0.1
lazy-object-proxy==1.3.1
llvmlite==0.23.1
locket==0.2.0
lxml==4.2.1
MarkupSafe==1.0
matplotlib==2.2.2
mccabe==0.6.1
mistune==0.8.3
mkl-fft==1.0.0
mkl-random==1.0.1
more-itertools==4.1.0
mpmath==1.0.0
msgpack-python==0.5.6
multipledispatch==0.5.0
navigator-updater==0.2.1
nbconvert==5.3.1
nbformat==4.4.0
networkx==2.1
nltk==3.3
nnlog==1.0.4
nose==1.3.7
nose-parameterized==0.6.0
notebook==5.5.0
numba==0.38.0
numexpr==2.6.5
numpy==1.14.3
numpydoc==0.8.0
odo==0.5.1
olefile==0.45.1
openpyxl==2.5.3
packaging==17.1
pandas==0.23.0
pandocfilters==1.4.2
parso==0.2.0
partd==0.3.8
path.py==11.0.1
pathlib2==2.3.2
patsy==0.5.0
pbr==4.2.0
pep8==1.7.1
pexpect==4.5.0
pickleshare==0.7.4
Pillow==5.1.0
pkginfo==1.4.2
pluggy==0.6.0
ply==3.11
prompt-toolkit==1.0.15
psutil==5.4.5
ptyprocess==0.5.2
py==1.5.3
pycodestyle==2.4.0
pycosat==0.6.3
pycparser==2.18
pycrypto==2.6.1
pycurl==7.43.0.1
pyflakes==1.6.0
Pygments==2.2.0
pylint==1.8.4
PyMySQL==0.9.2
pyodbc==4.0.23
pyOpenSSL==18.0.0
pyparsing==2.2.0
PySocks==1.6.8
pytest-arraydiff==0.2
pytest-astropy==0.3.0
pytest-doctestplus==0.1.3
pytest-openfiles==0.3.0
pytest-remotedata==0.2.1
python-dateutil==2.7.3
pytz==2018.4
PyWavelets==0.5.2
PyYAML==3.12
pyzmq==17.0.0
QtAwesome==0.4.4
qtconsole==4.3.1
QtPy==1.4.1
redis==3.0.1
requests==2.18.4
rope==0.10.7
ruamel-yaml==0.15.35
scikit-image==0.13.1
scikit-learn==0.19.1
scipy==1.1.0
seaborn==0.8.1
Send2Trash==1.5.0
simplegeneric==0.8.1
singledispatch==3.4.0.3
six==1.11.0
snowballstemmer==1.2.1
sortedcollections==0.6.1
sortedcontainers==1.5.10
Sphinx==1.7.4
sphinxcontrib-websupport==1.0.1
spyder==3.2.8
SQLAlchemy==1.2.7
statsmodels==0.9.0
stevedore==1.29.0
sympy==1.1.1
tables==3.4.3
tblib==1.3.2
terminado==0.8.1
testpath==0.3.1
text-unidecode==1.2
toolz==0.9.0
tornado==5.0.2
traitlets==4.3.2
typing==3.6.4
unicodecsv==0.14.1
urllib3==1.22
virtualenv==16.0.0
virtualenv-clone==0.3.0
virtualenvwrapper==4.8.2
wcwidth==0.1.7
webencodings==0.5.1
Werkzeug==0.14.1
widgetsnbextension==3.2.1
wrapt==1.10.11
xlrd==1.1.0
XlsxWriter==1.0.4
xlutils==2.0.0
xlwings==0.11.8
xlwt==1.2.0
xpinyin==0.5.6
yagmail==0.10.212
zict==0.1.3
第三方模块.txt
这里还有个问题:安装以及引用的第三方模块需要自己写吗?不需要!我们本机所有的模块其实可以用命令导出,换了电脑也可以用命令批量安装:这个命令要在命令行做
pip freeze > 第三方模块.txt # 将安装过的模块导出到指定文件
pip install -r 第三方模块.txt # 将文件内的模块批量安装, -r 代表遍历
注意
- 重启服务的时候,切记不要把程序再运行一次,那样是重新启动了一个服务而不是重新启动之前的服务,正确做法是 Rerun 一次已经运行的服务
- 有时候点右键运行如果出现,那么运行会报错,正常应该是,这个是 pycharm 的问题,只要出现'xxx in xxx.py',解决办法是点击最上面的 Run,选择 Run...,再选择要运行的代码
- 只写 ip:port 不成,还等加上相应路径,否则会报 404
- 路径不能有重复的,函数名也不能有重复的
- flask.request 就是 flask 收到的所有参数,打印的类型可以再后面加比如:flask.request.json
- server.run() 只能写一个,而且只能写在最后,在这之后的代码运行不到
衍生
其实呢,能做的仅仅如此么?我们之前是以 json 串为主,但是其实也可以写字符串,html 代码等等,这样就是一个小的网页咯
Python(七) —— mock接口开发的更多相关文章
- python语言(六)mock接口开发、发邮件、写日志、新Excel操作
一.urllib模块 urllib模块是一个标准模块,直接import urllib即可,在python3里面只有urllib模块,在python2里面有urllib模块和urllib2模块. url ...
- 基于Python的WEB接口开发与自动化测试 pdf(内含书签)
基于Python的WEB接口开发与自动化测试 目录 目 录O V目 录章 Python 学习必知 ................................................... ...
- python——flask常见接口开发(简单案例)
python——flask常见接口开发(简单案例)原创 大蛇王 发布于2019-01-24 11:34:06 阅读数 5208 收藏展开 版本:python3.5+ 模块:flask 目标:开发一个只 ...
- mock接口开发——flask模块
1.mock接口开发: #1.模拟没有开发好的接口,你可以模拟它,,,,,,,需要调用其他系统的接口 #2.给别人提供数据 2.步骤:1.安装pip install flask 2.导入模块--起服务 ...
- Python flask模块接口开发学习总结
引言 Flask 是一个简单且十分强大的Python web 框架.它被称为微框架,“微”并不是意味着把整个Web应用放入到一个Python文件,微框架中的“微”是指Flask旨在保持代码简洁且易于扩 ...
- Python学习之==>接口开发
一.开发接口的作用 1.在别的接口没有开发完成的时候可以模拟一些接口以便测试已经开发完成的接口,例如假的支付接口,模拟支付成功.支付失败. 2.了解接口是如何实现的:数据交互.数据返回 3.开发给别人 ...
- python进阶-mock接口
setting.py MYSQL_HOST='192.168.127.139' PASSWORD=' PORT=3306 USER='root' DB='stu' tools.py import py ...
- python使用笔记22--mock接口开发
1.mock接口开发 mock是模拟一个接口的意思 为了不阻止测试,开发一个接口,返回你想要的数据,模拟各种场景 需要安装第三方模块flask,flask是web轻量级开发框架 1.1 flask p ...
- 测试开发系列之Python开发mock接口(一)
什么是mock接口呢,举个栗子,你在一家电商公司,有查看商品.购物.支付.发 货.收获等等等一大堆功能,你是一个测试人员,测测测,测到支付功能的时候,你就要调用第三方支付接口了,真实支付,直接扣你支付 ...
随机推荐
- Configure vyatta
Username: vyatta Password: vyatta 配置网卡: 编辑: configure 内部网络IP地址配置:192.168.0.1 set interfaces ethernet ...
- Java-CAS 与原子类
CAS(Compare and Swap),即比较并替换,实现并发算法时常用到的一种技术. CAS 的思想很简单:三个参数,一个当前内存值 V.旧的预期值 A.即将更新的值 B,当且仅当预期值 A 和 ...
- 中间件 | Nginx实现动静分离
Nginx动静分离基本概述 动静分离,通过中间件将动静分离和静态请求进行分离: 通过中间件将动态请求和静态请求分离,可以建上不必要的请求消耗,同事能减少请求的延时. 通过中间件将动态请求和静态请求分离 ...
- redis多实例与主从同步及高级特性(数据过期机制,持久化存储)
redis多实例 创建redis的存储目录 vim /usr/local/redis/conf/redis.conf #修改redis的配置文件 dir /data/redis/ #将存储路径配置修改 ...
- Product - 产品经理 - 内容
特别说明 本文是已读书籍的学习笔记和内容摘要,原文内容有少部分改动,并添加一些相关信息,但总体不影响原文表达. - ISBN: 9787568041591 - https://book.douban. ...
- HTML5元素周期表
HTML5元素周期表 根元素 1. html 文档根元素 元数据和脚本 1. head HTML文档中的第一个元素.包含文档元数据 2. title 文档标题 3. meta 文档的元数据. meta ...
- 快速幂 -- cogs1437 转圈游戏
题目链接:http://cogs.pro:8081/cogs/problem/problem.php?pid=vJimmkqjW [题目描述] 思路:简单模拟,重点在于如何求这个轮数,由于k的范围过大 ...
- U盘ios系统制作
首先我们先安装软碟通,完成安装后打开软碟通,文件->打开,打开我们的iso镜像 步骤阅读 然后选择我们的U盘 步骤阅读 然后点击启动->写入硬盘映像 步骤阅读 写入方式有zip ...
- Java学习笔记-GUI
Java也提供图像化编程 图形化 GUI(图形用户界面) GUI Graphical User Interface(图形用户接口) 用图形的方式,来显示计算机操作的界面,这样更方便更直观 CLI Co ...
- SpringMVC 零配置 无web.xml
对SpringMVC启动流程的讲解 https://www.cnblogs.com/beiyan/p/5942741.html 与SpringMVC的整合 https://hanqunfeng.ite ...