网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
@pytest.mark.parametrize(‘data’,readJson())
def test_json_login(data):
r=requests.post(
url=data[‘request’][‘url’],
json=data[‘request’][‘body’])
assert r.json()==data[‘response’][0]
if name == ‘main’:
pytest.main([“-s”,“-v”,“test_json_login.py”])
## 3.yaml文件
再来看分离到Yaml文件的数据:
#用户名请求为空
“url”: “http://localhost:5000/login”
“body”: ‘{
“password”:“admin”,
“sex”:“男”,
“age”:18
}’
“expect”: ‘{
“message”: {
“username”: “用户名不能为空”
}
}’
#密码参数为空
“url”: “http://localhost:5000/login”
“body”: ‘{
“username”:“admin”,
“sex”:“男”,
“age”:18
}’
“expect”: ‘{
“message”: {
“password”: “账户密码不能为空”
}
}’
#校验性别参数的验证
“url”: “http://localhost:5000/login”
“body”: ‘{
“username”:“wuya”,
“password”:“admin”,
“sex”:“asdf”,
“age”:18
}’
expect: ‘{
“message”: {
“sex”: “性别只能是男或者女”
}
}’
#校验年龄是否是正整数
“url”: “http://localhost:5000/login”
“body”: ‘{
“username”:“wuya”,
“password”:“admin”,
“sex”:“男”,
“age”:“rrest”
}’
“expect”: ‘{
“message”: {
“age”: “年龄必须为正正数”
}
}’
#登录成功
“url”: “http://localhost:5000/login”
“body”: ‘{
“username”:“wuya”,
“password”:“admin”,
“sex”:“男”,
“age”:“18”
}’
“expect”: ‘{
“age”: 18,
“password”: “admin”,
“sex”: “男”,
“username”: “wuya”
}’
涉及到的测试代码为:
#!/usr/bin/env python
#!coding:utf-8
import pytest
import requests
import yaml
def readYaml():
with open(‘login.yaml’,‘r’) as f:
return list(yaml.safe_load_all(f))
@pytest.mark.parametrize(‘data’,readYaml())
def test_login(data):
r=requests.post(
url=data[‘url’],
json=json.loads(data[‘body’]))
assert r.json()==json.loads(data[‘expect’])
## 4.CSV
分离到CSV的文件内容为:
![图片](https://img-blog.csdnimg.cn/img_convert/584ef550726c86f39ee91d952ddab317.png)
涉及到的测试代码为:
#!/usr/bin/env python
#!coding:utf-8
import pytest
import requests
import csv
def readCsv():
data=list()
with open(‘login.csv’,‘r’) as f:
reader=csv.reader(f)
next(reader)
for item in reader:
data.append(item)
return data
@pytest.mark.parametrize(‘data’,readCsv())
def test_csv_login(data):
r=requests.post(
url=data[0],
json=json.loads(data[1]))
assert r.json()==json.loads(data[2])
最后来看分离到Excel的文件内容:
![图片](https://img-blog.csdnimg.cn/img_convert/ac9a32ba5d001a3d5d927cd974f7e293.png)
涉及到的测试代码为:
#!/usr/bin/env python
#!coding:utf-8
import pytest
import requests
import xlrd
def readExcel():
data=list()
book=xlrd.open_workbook(‘login.xls’)
sheet=book.sheet_by_index(0)
for item in range(1,sheet.nrows):
data.append(sheet.row_values(item))
return data
@pytest.mark.parametrize(‘data’,readExcel())
def test_excel_login(data):
r=requests.post(
url=data[0],
json=json.loads(data[1]))
assert r.json()==json.loads(data[2])
其实我们发现套路都是一样的,不管把数据分离到什么样的数据格式下,都得符合它的本质思想,也就是参数化的本质是对列表中的对象进行循环赋值,把握住这样的一个思想就可以了。整合上面的所有代码,完整代码为:
#!/usr/bin/env python
#!coding:utf-8
import pytest
import requests
import json
import yaml
import csv
import xlrd
def readJson():
return json.load(open(‘login.json’,‘r’))[‘item’]
def readYaml():
with open(‘login.yaml’,‘r’) as f:
return list(yaml.safe_load_all(f))
def readCsv():
data=list()
with open(‘login.csv’,‘r’) as f:
reader=csv.reader(f)
next(reader)
for item in reader:
data.append(item)
return data
def readExcel():
data=list()
book=xlrd.open_workbook(‘login.xls’)
sheet=book.sheet_by_index(0)
for item in range(1,sheet.nrows):
data.append(sheet.row_values(item))
return data
@pytest.mark.parametrize(‘data’,readJson())
def test_json_login(data):
r=requests.post(
url=data[‘request’][‘url’],
json=data[‘request’][‘body’])
assert r.json()==data[‘response’][0]
@pytest.mark.parametrize(‘data’,readYaml())
def test_yaml_login(data):
r=requests.post(
url=data[‘url’],
json=json.loads(data[‘body’]))
assert r.json()==json.loads(data[‘expect’])
@pytest.mark.parametrize(‘data’,readCsv())
def test_csv_login(data):
r=requests.post(
url=data[0],
json=json.loads(data[1]))
assert r.json()==json.loads(data[2])
@pytest.mark.parametrize(‘data’,readExcel())
def test_excel_login(data):
r=requests.post(
url=data[0],
json=json.loads(data[1]))
assert r.json()==json.loads(data[2])
执行后的结果信息为:
![图片](https://img-blog.csdnimg.cn/img_convert/a0c7cd6c6b13cd6d27e4a9ee3dd62736.png)
Pytest测试框架最强大的功能除了丰富的第三方插件外,还有就是它的Fixture和共享Fixture的conftest.py,下面具体来看被测试的接口代码:
from flask import Flask,make_response,jsonify,abort,request
from flask_restful import Api,Resource
from flask_httpauth import HTTPBasicAuth
from flask import Flask
from flask_jwt import JWT, jwt_required, current_identity
from werkzeug.security import safe_str_cmp
app=Flask(name)
app.debug = True
app.config[‘SECRET_KEY’] = ‘super-secret’
api=Api(app=app)
auth=HTTPBasicAuth()
@auth.get_password
def get_password(name):
if name==‘admin’:
return ‘admin’
@auth.error_handler
def authoorized():
return make_response(jsonify({‘msg’:“请认证”}),403)
books=[
{‘id’:1,‘author’:‘wuya’,‘name’:‘Python接口自动化测试实战’,‘done’:True},
{‘id’:2,‘author’:‘无涯’,‘name’:‘Selenium3自动化测试实战’,‘done’:False}
]
class User(object):
def init(self, id, username, password):
self.id = id
self.username = username
self.password = password
def str(self):
return “User(id=‘%s’)” % self.id
users = [
User(1, ‘wuya’, ‘asd888’),
User(2, ‘admin’, ‘admin’),
]
username_table = {u.username: u for u in users}
userid_table = {u.id: u for u in users}
def authenticate(username, password):
user = username_table.get(username, None)
if user and safe_str_cmp(user.password.encode(‘utf-8’), password.encode(‘utf-8’)):
return user
def identity(payload):
user_id = payload[‘identity’]
return userid_table.get(user_id, None)
jwt = JWT(app, authenticate, identity)
class Books(Resource):
decorators = [auth.login_required]
decorators=[jwt_required()]
def get(self):
return jsonify({‘status’:0,‘msg’:‘ok’,‘datas’:books})
def post(self):
if not request.json:
return jsonify({‘status’:1001,‘msg’:‘请求参数不是JSON的数据,请检查,谢谢!’})
else:
book = {
‘id’: books[-1][‘id’] + 1,
‘author’: request.json.get(‘author’),
‘name’: request.json.get(‘name’),
‘done’: True
}
books.append(book)
return jsonify({‘status’:1002,‘msg’: ‘添加书籍成功’,‘datas’:book}, 201)
class Book(Resource):
decorators = [auth.login_required]
decorators = [jwt_required()]
def get(self,book_id):
book = list(filter(lambda t: t[‘id’] == book_id, books))
if len(book) == 0:
return jsonify({‘status’: 1003, ‘msg’: ‘很抱歉,您查询的书的信息不存在’})
else:
return jsonify({‘status’: 0, ‘msg’: ‘ok’, ‘datas’: book})
def put(self,book_id):
book = list(filter(lambda t: t[‘id’] == book_id, books))
if len(book) == 0:
return jsonify({‘status’: 1003, ‘msg’: ‘很抱歉,您查询的书的信息不存在’})
elif not request.json:
return jsonify({‘status’: 1001, ‘msg’: ‘请求参数不是JSON的数据,请检查,谢谢!’})
elif ‘author’ not in request.json:
return jsonify({‘status’: 1004, ‘msg’: ‘请求参数author不能为空’})
elif ‘name’ not in request.json:
return jsonify({‘status’: 1005, ‘msg’: ‘请求参数name不能为空’})
elif ‘done’ not in request.json:
return jsonify({‘status’: 1006, ‘msg’: ‘请求参数done不能为空’})
elif type(request.json[‘done’])!=bool:
return jsonify({‘status’: 1007, ‘msg’: ‘请求参数done为bool类型’})
else:
book[0][‘author’] = request.json.get(‘author’, book[0][‘author’])
book[0][‘name’] = request.json.get(‘name’, book[0][‘name’])
book[0][‘done’] = request.json.get(‘done’, book[0][‘done’])
return jsonify({‘status’: 1008, ‘msg’: ‘更新书的信息成功’, ‘datas’: book})
def delete(self,book_id):
book = list(filter(lambda t: t[‘id’] == book_id, books))
if len(book) == 0:
return jsonify({‘status’: 1003, ‘msg’: ‘很抱歉,您查询的书的信息不存在’})
else:
books.remove(book[0])
return jsonify({‘status’: 1009, ‘msg’: ‘删除书籍成功’})
api.add_resource(Books,‘/v1/api/books’)
api.add_resource(Book,‘/v1/api/book/int:book_id’)
if name == ‘main’:
app.run(debug=True)
我们通过token的方式,首先需要授权,授权成功后才可以针对书籍这些接口进行操作,如添加删除以及查看所有的书籍信息,那么获取token这部分的代码完全可以放在conftest.py里面,具体源码为:
#!/usr/bin/env python
#!coding:utf-8
import requests
import pytest
@pytest.fixture()
def getToken():
‘’‘获取token’‘’
r=requests.post(
url=‘http://localhost:5000/auth’,
json={“username”:“wuya”,“password”:“asd888”})
return r.json()[‘access_token’]
Fixture一点需要考虑的是初始化与清理,也就是说在一个完整的测试用例中,都必须都得有初始化与清理的部分,这样才是一个完整的测试用例的。Fixture可以很轻松的来解决这部分,还有一点需要说的是Fixture的函数也可以和返回值整合起来,如添加书籍成功后,把数据ID返回来,下面就以查看书籍为案例,那么查看书籍前提是需要添加书籍,这样可以查看,最后把添加的书籍删除,这样一个测试用例执行完成后才符合它的完整流程,具体测试代码如下:
#!/usr/bin/env python
#!coding:utf-8
import pytest
import requests
def writeBookID(bookID):
with open(‘bookID’,‘w’) as f:
f.write(str(bookID))
@pytest.fixture()
def getBookID():
with open(‘bookID’,‘r’) as f:
return f.read()
def addBook(getToken):
r=requests.post(
url=‘http://localhost:5000/v1/api/books’,
json={“author”: “无涯”,“done”: False,“name”: “Selenium3自动化测试实战”},
headers={‘Authorization’:‘JWT {0}’.format(getToken)})
print(‘添加书籍:\n’,r.json())
writeBookID(r.json()[0][‘datas’][‘id’])
def delBook(getToken,getBookID):
r=requests.delete(
url=‘http://localhost:5000/v1/api/book/{0}’.format(getBookID),
headers={‘Authorization’:‘JWT {0}’.format(getToken)})
print(‘删除书籍:\n’,r.json())
@pytest.fixture()
def init(getToken,getBookID):
addBook(getToken)
yield
delBook(getToken,getBookID)
def test_get_book(init,getToken,getBookID):
r=requests.get(
url=‘http://localhost:5000/v1/api/book/{0}’.format(getBookID),
headers={‘Authorization’:‘JWT {0}’.format(getToken)})
print(‘查看书籍:\n’,r.json())
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上软件测试知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
/v1/api/book/{0}'.format(getBookID),
headers={‘Authorization’:‘JWT {0}’.format(getToken)})
print(‘查看书籍:\n’,r.json())
[外链图片转存中…(img-Pe0Y3b12-1715304004008)]
[外链图片转存中…(img-ZOf2RlrB-1715304004008)]
[外链图片转存中…(img-Z0PtVfo0-1715304004009)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上软件测试知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新