3.1 设计excel结构
根据个人需要设计
case编号 | 用例名称 | 是否执行 | 是否是链路 | 前置条件 | 依赖key | url或链路名称 | method | 请求参数 | header操作 | 预期结果方式 | 预期结果 | 执行结果 | 返回数据 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Aha_001 | 名称1 | yes | /login/phone | post | {“phone”: “15xxxxxx”, |
“password”: “123456”} | yes | code_msg | | pass | | | Aha_002 | 名称2 | no | yes | Aha_001>data.pageData.[0].id | projectId | upload_user_photo | get | | | code | 200 | | | | Aha_003 | 名称3 | yes | no | Aha_004>data.userId | | /userInfo/ | | | | json | | failed | |
3.2 excel操作
写得时候需要调一调,就是+1或者-1的区别。。因为有的时候从0开始,有的时候从1开始
# coding=utf-8
import openpyxl
import sys
import os
sys.path.append(os.path.realpath('..'))
class OperateExcel:
def load_excel(self):
"""
加载excel
"""
open_excel = openpyxl.load_workbook(r"../Case/case.xlsx")
return open_excel
def get_sheet_data(self, index=None):
"""
加载所有sheet的内容
"""
sheet_name = self.load_excel().sheetnames
if index is None:
index = 0
data = self.load_excel()[sheet_name[index]]
return data
def get_cell_value(self, row, cols):
"""
获取某一个单元格的内容
"""
data = self.get_sheet_data().cell(row=row, column=cols).value
return data
def get_rows(self):
"""
获取行数
"""
row = self.get_sheet_data().max_row
return row-1
def get_row_value(self, row):
"""
获取某行内容
"""
value_list = []
for i in self.get_sheet_data()[row]:
value_list.append(i.value)
return value_list
def write_data(self, row, cols, value):
"""
写入数据
:param row:
:param cols:
:param value:
:return:
"""
wb = self.load_excel()
wr = wb.active
wr.cell(row, cols, value)
wb.save(r"../Case/case.xlsx")
def get_columns_data(self, col_no=None):
"""
获取某列的所有值
:param col_no: 列号, str
:return:
"""
columns_list = []
if col_no is None:
col_no = 'A'
columns_list_data = self.get_sheet_data()[col_no]
for i in columns_list_data:
columns_list.append(i.value)
return columns_list
def get_row_number(self, case_id):
"""
获取行号
:return:
"""
number = 1
cols_data = self.get_columns_data()
for col_data in cols_data:
if case_id == col_data:
return number
number = number + 1
def get_excel_data(self):
"""
获取excel里所有的数据
:return:
"""
data_list = []
for i in range(self.get_rows()):
# 从1开始数,所以第二行是2
data_list.append(self.get_row_value(i+2))
return data_list
# 单例模式,只需实例化一次
excel_data = OperateExcel()
if __name__ == "__main__":
excel = OperateExcel()
print(excel.get_row_number("imooc_002"))
3.3 ini文件操作
ini文件就是配置文件,记录一些常用参数比方说host地址
[server]
host=https://aha.cn/aha_test
phone=15xxxxxxxxx
password=123456
[case]
case_no=0
case_name=1
is_run=2
is_link=3
is_depend=4
depend_key=5
url=6
method=7
request_data=8
header_method=9
expect_method=10
expect_result=11
result=12
res_data=13
[pic_file1]
file_name = p130865532.jpg
file_path = C:\Users\zero\PycharmProjects\auto_interface_test\File
file_type = image/jpeg
读取ini文件
# coding = utf-8
import os
import sys
sys.path.append(os.path.realpath('..'))
import configparser
class ReadIni:
def load_ini(self):
file_path = r'..\Config\server.ini'
cf = configparser.ConfigParser()
cf.read(file_path, encoding="utf-8-sig")
return cf
def get_value(self, key, section=None):
"""
获取ini里的值
:param key:
:param section:
:return:
"""
if section is None:
section = 'server'
cf = self.load_ini()
try:
value = cf.get(section, key)
except Exception as e:
print("没有获取到值")
value = None
print(e)
return value
return value
read_ini = ReadIni()
if __name__ == "__main__":
ri = ReadIni()
data = ri.get_value('result', 'case')
print(data)
3.4 run main
3.4.1 前置条件
首先要搞清楚有几种请求
如果是post和有参数的get请求,就需要三个信息。比方说发送评论,需要先获取到评论id,评论id又是通过上一个请求“获取所有评论”获得的。所以就是三个信息:上一请求的返回参数,提取参数的规则,依赖参数。就是表格中的返回数据、前置条件、依赖参数。(名称自己瞎起的,领会精神)
如果是不带参数的get请求,比方说host/project/23这样的url,就不需要有依赖参数,拼接一下url就可以了。
那么代码中就是:
if is_depend is not None:
depend_data = load_dependency(is_depend)
if depend_key is not None:
request_data[depend_key] = depend_data
print(request_data)
else:
url = url + str(depend_data)
提取所需的前置参数值,precondition.py
规则是imooc_001>data:banner:id
先使用get_dependent_data获取imooc_001这条用例中的返回数据集,然后通过后面的规则通过get_dependent_value提取所需的参数值,然后整合到load_dependency中方便调用。
# coding = utf-8
import os
import sys
from jsonpath_rw import parse
import json
sys.path.append(os.path.realpath('..'))
from Util.operate_excel import excel_data
def split_data(data):
"""
:param data: excel中的内容
:return:
"""
# data = imooc_001>data:banner:id
case_id = data.split(">")[0]
data_rule = data.split(">")[1]
return case_id, data_rule
def get_dependent_data(data):
"""
从excel中获取数据集
:param data: excel中的内容
:return:
"""
case_id = split_data(data)[0]
row_number = excel_data.get_row_number(case_id)
row_value = excel_data.get_cell_value(row_number, 14)
return row_value
def get_dependent_value(data, rule):
"""
从数据集中提取所需的字段
:param data: 请求返回的数据
:param rule: 匹配规则:data.banner.[0].id
:return:
"""
data = json.loads(data)
for i in parse(rule).find(data):
return i.value
#return [i.value for i in parse(rule).find(data)][0]
def load_dependency(data):
response_data = get_dependent_data(data)
rule = split_data(data)[1]
return get_dependent_value(response_data, rule)
3.4.2 链路
(这部分是自己瞎写的)
因为有一些用例需要通过多个请求完成,所以把这些请求整合到一个方法中,直接调用方法。
我使用反射完成。
if is_link is not None:
#url=upload_user_photo
execute_link = getattr(link, url)
res = execute_link(phone, password, file_name, file_path, file_type)
就是先新建一个link.py文件,调用里面的方法。
下面用上传头像举例:
# coding = utf-8
import os
import sys
sys.path.append(os.path.realpath('..'))
import requests
from Base.base_request import request
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
class Link:
def upload_user_photo(*args):
"""
上传头像
:param phone:
:param password:
:param filename:
:param path:
:param pic_type: image/jpeg
:return:
"""
# 登录
proxies = {'http': "http://localHost:8888", 'https': 'http://localhost:8888'}
headers = {'Content-Type': 'application/json'}
login_url = "/login/phone"
data1 = {'phone': args[1], 'password': args[2]}
res_login = request.run_main('post', login_url, data1, headers, proxies, False)
print(res_login)
token = res_login['data']['token']
headers['Authorization'] = token
# 获取向COS上传公共文件签名
signature_url = "/userInfo/avatar/sign/upload"
data2 = {
"filename": args[3]
}
res_signature = request.run_main('get', signature_url, data2, headers, proxies, False)
print(res_signature)
key = res_signature['data']['filename']
policy = res_signature['data']['policy']
q_ak = res_signature['data']['secretId']
q_key_time = res_signature['data']['keyTime']
q_sign_algorithm = "sha1"
q_signature = res_signature['data']['signature']
# 上传图片到服务器
pic_url = "https://aha-public-1257019972.cos.ap-shanghai.myqcloud.com"
with open(args[4], "rb") as f_abs:
body = {
"key": (None, key),
"policy": (None, policy),
"q-ak": (None, q_ak),
"q-key-time": (None, q_key_time),
"q-sign-algorithm": (None, q_sign_algorithm),
"q-signature": (None, q_signature),
"file": (args[3], f_abs, args[5])
}
res_pic = requests.post(pic_url, files=body, proxies=proxies, verify=False)
print(res_pic.headers)
location = res_pic.headers['Location']
# 修改用户信息
modify_user_info_url = "/userInfo/me"
modify_user_info_data = {
"avatarUrl": location
}
res_put = request.run_main("put", modify_user_info_url, modify_user_info_data, headers, proxies, False)
print(res_put)
return res_put
3.4.3 判断case是否通过
首先要知道有几种判断方法,可以通过code_msg、code、json结构判断。
if expect_method == 'code_msg':
config_message = read_expected_msg(url, code)
if message == config_message:
print("测试case通过")
excel_data.write_data(i + 2, int(read_ini.get_value('result', 'case'))+1, "pass")
excel_data.write_data(i + 2, int(read_ini.get_value('res_data', 'case'))+1, json.dumps(res))
else:
print("测试case失败")
excel_data.write_data(i + 2, int(read_ini.get_value('result', 'case'))+1, "fail")
excel_data.write_data(i + 2, int(read_ini.get_value('res_data', 'case'))+1, json.dumps(res))
if expect_method == 'code':
if expect_result == code:
print("测试case通过")
excel_data.write_data(i + 2, int(read_ini.get_value('result', 'case'))+1, "pass")
excel_data.write_data(i + 2, int(read_ini.get_value('res_data', 'case'))+1, json.dumps(res))
else:
print("测试case失败")
excel_data.write_data(i + 2, int(read_ini.get_value('result', 'case'))+1, "fail")
excel_data.write_data(i + 2, int(read_ini.get_value('res_data', 'case'))+1, json.dumps(res))
if expect_method == 'json':
if code == "200":
status = "success"
else:
status = "error"
expect_result = get_result_json(url, status)
if check_json_format(res, expect_result):
print("测试case通过")
excel_data.write_data(i + 2, int(read_ini.get_value('result', 'case'))+1, "pass")
excel_data.write_data(i + 2, int(read_ini.get_value('res_data', 'case'))+1, json.dumps(res))
else:
print("测试case失败")
excel_data.write_data(i + 2, int(read_ini.get_value('result', 'case'))+1, "fail")
excel_data.write_data(i + 2, int(read_ini.get_value('res_data', 'case'))+1, json.dumps(res))
if expect_method is None:
excel_data.write_data(i + 2, int(read_ini.get_value('res_data', 'case')) + 1, json.dumps(res))
a. code_msg
举个栗子。就是状态码和返回信息之间的对应关系。
code_msg.json
"/login/phone": [
{"200": "登录成功"},
{"302": "用户名或密码错误!"},
{"301": "用户不存在!"},
{"701": "访问次数超限!"}
问题就是如何提取,和判断是否对应。
def read_expected_msg(url, code):
data = get_value(url, "code_message.json")
if data is not None:
# data是一个list
for i in data:
message = i.get(code)
if message is not None:
return message
return None
b. code
c. json结构
这个就是看返回的结果的json结构是否和预期的json结构一致,所以也是有一个json文件记录预期json结构。
expect_result.json
根据状态(success/error)区分预期的结果
def get_result_json(url, status):
data = get_value(url, "expect_result.json")
if data is not None:
# data是一个list
for i in data:
message = i.get(status)
if message is not None:
return message
return None
def check_json_format(dict1, dict2):
"""
校验json格式
:return:
"""
# 参数必须为字典,如果有一个不是字典,就返回false
if isinstance(dict1, dict) and isinstance(dict2, dict):
cmp_dirt = DeepDiff(dict1, dict2, ignore_order=True).to_dict()
#print(cmp_dirt)
if cmp_dirt.get("dictionary_item_added"):
return False
else:
return True
return False
未完待续,其实我不是很清楚如何管理case。。。