pytest之接口自动化实践
一.搭建接口自动化测试框架
目录分层:
1.common:放置常用公共方法,例如:操作yaml文件的模块、读取配置文件模块等
2.config:存放配置文件:例如:config.ini文件
3.logs:存放日志文件
4.report:存放生成的报告
5.tmep:allure生成的json报告,通过它来生成最终的报告
6.testcase:测试用例所在的目录
7.data:以yaml的方式放测试用例数据
8.extract.yaml:存放用例之间数据关联的数据
9.pytest.ini:pytest的配置文件
10.main.py:主调用入口
二、具体实现和代码
【难点】
数据驱动:
-参数化:@pytest.mark.parametrize()
-数据读取:yaml保存用例数据,通过封装的读取yaml的方法来获取测试数据,通过写入yaml文件是实现用例之间数据关联
公共变量:在congfig下创建config.ini,里面保存公共变量
import pytest
import logging
import json
import requests
import time
# from common.login import login
from common.merge import Merge
from common.yaml_util import yamlUtil
from common.readconfig import readconfig
# login = login()
log = logging.getLogger()
@pytest.fixture(scope="module")
def login():
log.info("...........登录获取token...........")
args = yamlUtil().read_extract_yaml("/Users/dongshuai/PycharmProjects/interface/testcase/data/stu_login_data.yaml")
url = args[0]["url"]
palyloads = json.dumps(args[0]["payload"])
headers = args[0]["headers"]
res = requests.post(url=url,headers=headers,data=palyloads)
header_token = {}
header_token["token"] = json.loads(res.text)["data"]["token"]
header_token["requestid"] = str(int(time.time()))
yield header_token
log.info("...........登录完获取token返回...........")
class Test_observatory():
def setup_class(self):
# yamlUtil().clear_yaml("/Users/dongshuai/PycharmProjects/interface/extract.yaml")
yamlUtil().clear_yaml(readconfig("test","file_extract.yaml"))
log.info("\n.....................模块observatory开始.....................")
def teardown_class(self):
log.info("\n.....................模块observatory结束.....................")
# @pytest.mark.parametrize("args",yamlUtil().read_extract_yaml("/Users/dongshuai/PycharmProjects/interface/testcase/data/MicroClassList.yaml"))
@pytest.mark.parametrize("args",yamlUtil().read_extract_yaml(readconfig("test","file_MicroClassList.yaml")))
def test_MicroClassList(self,args,login):
log.info('..........'+args["interfaceName"]+"..........")
url = args["url"]
payload = json.dumps(args["payload"])
headers = Merge(args["headers"],login) #合并字典
res = requests.post(url=url,headers=headers,data=payload)
res_text = json.loads(res.text)
# yamlUtil().write_extract_yaml(res_text["data"]["list"][0]["resid"])
#判断用例中ecode是否为true,是的话,就将提取数据存入yaml
print(args["validata"]["first"])
if args["validata"]["first"] == True: #这里的True得写成bool的而不是str的
map = {}
print(res_text)
if res_text["data"]["list"][0]["resid"]:
map["resid"]=res_text["data"]["list"][0]["resid"]
yamlUtil().write_extract_yaml(map)
assert json.loads(res.text)["meta"]["ecode"] == args["validata"]["ecode"],res.text
# @pytest.mark.parametrize("args",yamlUtil().read_extract_yaml("/Users/dongshuai/PycharmProjects/interface/testcase/data/KnowledgeList.yaml"))
@pytest.mark.parametrize("args",yamlUtil().read_extract_yaml(readconfig('test',"file_KnowledgeList.yaml")))
def test_Knowledge_list(self,args):
# log.info('..........'+args["interfaceName"]+"..........")
# value = yamlUtil().read_extract_yaml("/Users/dongshuai/PycharmProjects/interface/extract.yaml")
value = yamlUtil().read_extract_yaml(readconfig("test","file_extract.yaml"))
print(value)
if __name__ == '__main__':
pytest.main(["-vs"])
#用例1:
-
interfaceName: 用例1-推荐微课列表
url: http://stupad-stress.xk12.cn/api/pad/v1/observatory/microlist
payload: {
"isfirst": 1,
"kid": 1734,
"ktype": 1,
"pagesize": 10,
"vs": "2.12.0.2-debug",
"vc": 981,
"ua": "OKAY_EBOOK_S4_OKUI_5.2.0.0_20200518_T",
"os": "Galileo",
"sw": "1280",
"sh": "800",
"iccid": "89860617030077789660",
"serial": "f31eda17",
"channel": "pad",
"udid": "A63330A4258DF59B72E6863C88DFDE68",
"screen_pattern": "1",
"imei": "0",
"mac": "02:00:00:00:00:00",
"contype": 3
}
headers: {
'Content-Type': 'application/json',
'requestid': '021619190842',
'token': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOiI4OTg2MyIsInN5c3RlbUlkIjoiODE5NTEwNTU3NDEiLCJvcmdJZCI6IjgwIiwidGltZXN0YW1wIjoiMTYxOTE5MDc1NTEwMCJ9.rmQYKPvEgA0OvGwnpEsNJ4dP8qPKMZOhvu_k1g1n8Fg'
}
validata: {
"ecode": 0,
"emsg": "",
"debug": null,
"first": true
}
#用例2:
-
interfaceName: 用例2-推荐微课列表
url: http://stupad-stress.xk12.cn/api/pad/v1/observatory/microlist
payload: {
"isfirst": "",
"kid": 1734,
"ktype": 1,
"pagesize": 10,
"vs": "2.12.0.2-debug",
"vc": 981,
"ua": "OKAY_EBOOK_S4_OKUI_5.2.0.0_20200518_T",
"os": "Galileo",
"sw": "1280",
"sh": "800",
"iccid": "89860617030077789660",
"serial": "f31eda17",
"channel": "pad",
"udid": "A63330A4258DF59B72E6863C88DFDE68",
"screen_pattern": "1",
"imei": "0",
"mac": "02:00:00:00:00:00",
"contype": 3
}
headers: {
'Content-Type': 'application/json',
'requestid': '021619190842',
'token': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOiI4OTg2MyIsInN5c3RlbUlkIjoiODE5NTEwNTU3NDEiLCJvcmdJZCI6IjgwIiwidGltZXN0YW1wIjoiMTYxOTE5MDc1NTEwMCJ9.rmQYKPvEgA0OvGwnpEsNJ4dP8qPKMZOhvu_k1g1n8Fg'
}
validata: {
"ecode": 0,
"emsg": "",
"debug": null,
"first": true
}
#用例3:
-
interfaceName: 用例3-推荐微课列表
url: http://stupad-stress.xk12.cn/api/pad/v1/observatory/microlist
payload: {
"kid": 1734,
"ktype": 1,
"pagesize": 10,
"vs": "2.12.0.2-debug",
"vc": 981,
"ua": "OKAY_EBOOK_S4_OKUI_5.2.0.0_20200518_T",
"os": "Galileo",
"sw": "1280",
"sh": "800",
"iccid": "89860617030077789660",
"serial": "f31eda17",
"channel": "pad",
"udid": "A63330A4258DF59B72E6863C88DFDE68",
"screen_pattern": "1",
"imei": "0",
"mac": "02:00:00:00:00:00",
"contype": 3
}
headers: {
'Content-Type': 'application/json',
'requestid': '021619190842',
'token': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOiI4OTg2MyIsInN5c3RlbUlkIjoiODE5NTEwNTU3NDEiLCJvcmdJZCI6IjgwIiwidGltZXN0YW1wIjoiMTYxOTE5MDc1NTEwMCJ9.rmQYKPvEgA0OvGwnpEsNJ4dP8qPKMZOhvu_k1g1n8Fg'
}
validata: {
"ecode": 0,
"emsg": "",
"debug": null,
"first": true
}
#用例4:
-
interfaceName: 用例4-推荐微课列表
url: http://stupad-stress.xk12.cn/api/pad/v1/observatory/microlist
payload: {
"isfirst":"#",
"kid": 1734,
"ktype": 1,
"pagesize": 10,
"vs": "2.12.0.2-debug",
"vc": 981,
"ua": "OKAY_EBOOK_S4_OKUI_5.2.0.0_20200518_T",
"os": "Galileo",
"sw": "1280",
"sh": "800",
"iccid": "89860617030077789660",
"serial": "f31eda17",
"channel": "pad",
"udid": "A63330A4258DF59B72E6863C88DFDE68",
"screen_pattern": "1",
"imei": "0",
"mac": "02:00:00:00:00:00",
"contype": 3
}
headers: {
'Content-Type': 'application/json',
'requestid': '021619190842',
'token': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOiI4OTg2MyIsInN5c3RlbUlkIjoiODE5NTEwNTU3NDEiLCJvcmdJZCI6IjgwIiwidGltZXN0YW1wIjoiMTYxOTE5MDc1NTEwMCJ9.rmQYKPvEgA0OvGwnpEsNJ4dP8qPKMZOhvu_k1g1n8Fg'
}
validata: {
"ecode": 0,
"emsg": "",
"debug": null,
"first": true
}
yaml_util.py:
import yaml,os
'''
封装读取yaml的方法
'''
class yamlUtil():
def __init__(self):
pass
# 读取yaml
def read_extract_yaml(self,yaml_file):
with open(yaml_file,encoding="utf-8") as f:
value = yaml.load(f,Loader=yaml.FullLoader)
# print(value)
return value
#写入yaml,做数据关联时用
def write_extract_yaml(self,extract_dict):
with open("/Users/dongshuai/PycharmProjects/interface/extract.yaml","a") as f:
yaml.dump(extract_dict,f,allow_unicode=True) #这里需要注意,不然保存的yaml中文是乱码
f.close()
#清空yaml数据
def clear_yaml(self,text_path):
with open(text_path, 'w') as f1:
f1.seek(0)
f1.truncate()
print("清空yaml数据")
if __name__ == '__main__':
yamlUtil().write_extract_yaml("斤斤计较军、")
readconfig.py:
import configparser
import os
'''
读取配置文件
'''
def readconfig(section,value):
root_dir = os.path.abspath("../")
cf = configparser.ConfigParser()
cf.read(root_dir+"/config/config.ini")
value = cf.get(section,value)
return value
- main.py:
import pytest
import os
if __name__ == '__main__':
pytest.main()
os.system("cd "+os.getcwd()+" | allure generate ./temp -o ./report --clean")