一、jsonpath
jsonpath是类似于xpath的一种定位方式,用于接口返回的数据定位,通过jsonpath定位到的内容以list形式进行返回,如果表达式出现错误,则返回布尔类型值False。
1、jsonpath安装
命令行中输入:pip install jsonpath
2、jsonpath基本格式规范
$ 表示根节点,也是所有jsonpath表达式的开始
. 表示获取子节点
… 表示获取所有符合条件的内容
* 代表所有的元素节点
[] 表示迭代器的标示(可以用于处理下标等情况)
[,] 表示多个结果的选择
?() 表示过滤操作
@ 表示当前节点
3、jsonpath举例
代码(json_path下的demo.py)如下:
'''
1、返回list形式
2、出现错误,返回布尔类型
'''
import jsonpath
# 定位数据
data = {
"store": {
"book": [
{
"category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{
"category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99
},
{
"category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99
},
{
"category": "fiction",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99
}
],
"bicycle": {
"color": "red",
"price": 19.95
}
},
"expensive": 10
}
# 基于jsonpath获取元素
'''
$ 根节点
.. 所有符合条件的内容
. 子节点
* 所有的元素节点
[] 迭代器的表示(用于处理下标等情况)
[,] 多个结果的选择
?() 过滤操作
@ 当前节点
'''
# 获取某个值
bike = jsonpath.jsonpath(data, 'store.bicycle.color')
# 返回列表
print(bike)
# 列表通过索引取值
print(bike[0])
# store下所有price的值
price = jsonpath.jsonpath(data, '$.store..price')
print(price)
# , 连接操作符,连接第一个和第四个值
book_price = jsonpath.jsonpath(data, '$.store.book[0,3].price')
print(book_price)
# 过滤操作,过滤价格大于10的物品
book_1 = jsonpath.jsonpath(data, '$.store[..?(@.price>10)]')
print(book_1)
二、关键字封装
对接口测试的基本操作进行封装。
代码(api_key.py)如下:
import json
import jsonpath
import requests
class ApiKey:
# get请求封装
def get(self, url, params=None, **kwargs):
return requests.get(url=url, params=params, **kwargs)
# post请求封装
def post(self, url, data=None, **kwargs):
return requests.post(url=url, data=data, **kwargs)
# jsonpath获取值封装
def get_text(self, data, key):
# json数据转换为字典
json_data = json.loads(data)
value = jsonpath.jsonpath(json_data, '$..{0}'.format(key))
return value[0]
三、基于unittest实现接口自动化测试
1、测试用例
此处以登录请求为例,调用关键字进行post请求,数据以yaml文件形式存放。
代码(test_case_unittest01.py)如下:
import unittest
from ddt import ddt, file_data
from api_keyword.api_key import ApiKey
@ddt
class Test_ApiCase(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
cls.ak = ApiKey()
@file_data('../data/user.yaml')
def test_1(self, user, msg):
# 请求接口
url = 'http://39.98.138.157:5000/api/login'
# 请求参数
userInfo = {
'username': user['username'],
'password': user['password']
}
res = self.ak.post(url=url, json=userInfo)
print(res.text)
# 获取响应结果
msg1 = self.ak.get_text(res.text, 'msg')
print(msg)
# 断言
self.assertEqual(msg1, msg, msg='异常')
if __name__ == '__main__':
unittest.main()
2、yaml文件
代码(user.yaml)如下:
-
user:
username: admin
password: '123456'
msg: success
-
user:
username: admin1
password: '1234561'
msg: 用户名或密码错误
-
user:
username: admin2
password: '1234562'
msg: 用户名或密码错误
四、基于pytest+allure实现接口自动化测试
1、pytest安装
pip install pytest
2、allure安装
解压压缩包
解压后将bin目录地址添加进环境变量
配置pytest的allure
命令行中输入:pip install allure-pytest
3、yaml数据
yaml与unittest的yaml一致
4、yaml数据解读
pytest没有unittest的ddt来接读yaml数据,因此需要额外添加一个模块来解读yaml文件。
代码(yaml_driver.py)如下:
import yaml
def load_yaml(path):
file = open(path, 'r', encoding='utf-8')
data = yaml.load(file, Loader=yaml.FullLoader)
return data
4、关键字封装
相比于之前的key增加了@allure.step()来显示步骤,使测试报告更加清晰,代码(api_key.py)如下:
import allure
import json
import jsonpath
import requests
class ApiKey:
@allure.step("发送get请求")
def get(self, url, params=None, **kwargs):
return requests.get(url=url, params=params, **kwargs)
@allure.step("发送post请求")
def post(self, url, data=None, **kwargs):
return requests.post(url=url, data=data, **kwargs)
@allure.step("获取返回结果字典值")
def get_text(self, data, key):
# 数据转换成json类型
json_data = json.loads(data)
value = jsonpath.jsonpath(json_data, '$..{0}'.format(key))
return value[0]
5、conftest配置
进行初始配置,此处为了防止中文乱码出现进行配置。
代码(conftest.py)如下:
def pytest_collection_modifyitems(items):
"""
测试用例收集完成时,将收集到的item的name和nodeid的中文显示在控制台上
"""
for item in items:
item.name = item.name.encode("utf-8").decode("unicode_escape")
item._nodeid = item.nodeid.encode("utf-8").decode("unicode_escape")
6、测试用例
此处实现pytest下的两个测试用例的执行。
代码(test_case03_allure.py)如下:
import pytest
import allure
from pytest_demo.api_keyword.api_key import ApiKey
from pytest_demo.data_driver import yaml_driver
@allure.epic("接口测试")
class Test_ApiCase():
@allure.story("01.登录接口测试")
@pytest.mark.parametrize('userdata', yaml_driver.load_yaml('./data/user.yaml'),
ids=[
"输入正确账号密码,登录成功",
"输入错误账号密码,登录失败0",
"输入错误账号密码,登录失败1"
])
def test_1(self, userdata):
# 初始化工具类
ak = ApiKey()
# 请求接口
url = 'http://39.98.138.157:5000/api/login'
# 请求参数
userInfo = {
'username': userdata['user']['username'],
'password': userdata['user']['password']
}
res = ak.post(url=url, json=userInfo)
print(res.text)
with allure.step("校验响应结果"):
# 获取响应结果
msg = ak.get_text(res.text, 'msg')
print(msg)
# 断言
assert msg == userdata['msg']
@allure.story("02.个人用户查询接口")
def test_2_getuserinfo(self):
ak = ApiKey()
with allure.step("发送接口登录请求"):
# 请求接口
url = 'http://39.98.138.157:5000/api/login'
# 请求参数
userInfo = {
'username': 'admin',
'password': '123456'
}
res = ak.post(url=url, json=userInfo)
with allure.step("发送个人查询接口请求"):
url = 'http://39.98.138.157:5000/api/getuserinfo'
headers = {
'token': res.json()['token']
}
res1 = ak.get(url=url, headers=headers)
print(res1.text)
with allure.step("返回结果校验"):
name = ak.get_text(res1.text, 'nikename')
# 断言
assert "风清扬1" == name
7、执行
执行入口代码(main_run.py)如下:
import os
import pytest
def run():
pytest.main(['-v', './case/test_case03_allure.py',
'--alluredir', './result', '--clean-alluredir'])
os.system('allure generate ./result/ -o ./report_allure/ --clean')
if __name__ == '__main__':
run()
8、allure测试报告
浏览器打开html
安装包及源码下载地址
链接:https://pan.baidu.com/s/1t46vfl0W6YZG3yjK17iJpw
提取码:r0va
–来自百度网盘超级会员V2的分享