【接口自动化连载】使用yaml配置文件自动生成接口case
直接上干货撸代码,有一些是通用的工具类代码,一次性封装永久使用,期待大家的关注,一起加油!!!
配置文件
根据不同的业务需求进行配置,例如Goods服务、Order服务分开配置,每个服务下配置接口信息,每个接口文件里配置各种case。
/conf/GooodsApi/get_shop_info.yaml
# 公共参数
case_common:
allureEpic: 商品接口
allureFeature: 店铺信息
allureStory: 店铺信息
get_user_info_01:
host: https://goodsapi.e.weibo.com
url: /mp/shop/getShopInfo
method: GET
detail: 获取商家店铺信息
headers:
# Content-Type: multipart/form-data;
# 这里cookie的值,写的是存入缓存的名称
# cookie: $cache{login_cookie}
# 请求的数据,是 params 还是 json、或者file、data
requestType: params
# 是否执行,空或者 true 都会执行
is_run:
data:
{"shop_id": xxxx}
# 是否有依赖业务,为空或者false则表示没有
dependence_case: False
# 依赖的数据
dependence_case_data:
assert:
# 断言接口状态码
errorCode:
jsonpath: $.code
type: ==
value: 0
AssertType:
sql:
通用工具类
文件操作
/utils/file_operate.py
import os
def get_root_path():
"""获取(项目)根目录"""
return os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
def ensure_path_sep(path):
"""兼容windows和Linux不同环境的操作系统路径"""
if '/' in path:
path = os.sep.join(path.split('/'))
if '\\' in path:
path = os.sep.join(path.split('\\'))
return get_root_path() + path
def get_all_yaml_files(file_path, yaml_data_switch=False):
"""获取配置的yaml文件路径"""
file_name = []
for root, dir, files in os.walk(file_path):
for _file_path in files:
path = os.path.join(root, _file_path)
if yaml_data_switch:
if 'yaml' in path or '.yml' in path:
file_name.append(path)
file_name.append(path)
return file_name
操作yaml
/utils/yaml_control.py
Class YamlControl:
def __init__(self, file_str):
self.file_str = file_str
def file_is_exists(self, filepath):
if os.path.exists(filepath):
return True
return False
def read_yaml_data(self):
"""获取yaml文件数据"""
if self.file_is_exists(self.file_str):
data = open(self.file_str, "r", encoding="UTF-8")
yaml_data = yaml.load(data, Loader = yaml.FullLoader)
else:
raise FileNotFoundError("文件路径不存在")
return yaml_data
def save_yaml_data(self, file_path, data):
if self.file_is_exists(file_path):
with open(file_path, 'w') as file:
yaml.safe_dump(data, file, default_flow_style=False)
else:
raise FileNotFoundError("文件路径不存在")
自动生成用例代码
/utils/case_automatic_genration.py
import os
from utils.read_file_tools import get_all_yaml_files, ensure_path_sep
from utils.yaml_control import YamlControl
from utils.test_case import write_testcase_file
class TestCaseAutomaticGeneration:
def __init__(self):
self.yaml_case_data = None
self.file_path = None
@property
def allure_epic(self):
_allure_epic = self.yaml_case_data.get("case_common").get("allureEpic")
assert _allure_epic is not None, (
"用例中 allureEpic 为必填项,请检查用例内容, 用例路径:'%s'" % self.file_path
)
return _allure_epic
@property
def allure_feature(self):
_allure_feature = self.yaml_case_data.get("case_common").get("allureFeature")
assert _allure_feature is not None, (
"用例中 allureFeature 为必填项,请检查用例内容, 用例路径:'%s'" % self.file_path
)
return _allure_feature
@property
def allure_story(self):
_allure_story = self.yaml_case_data.get("case_common").get("allureStory")
assert _allure_story is not None, (
"用例中 allureStory 为必填项,请检查用例内容, 用例路径:'%s'" % self.file_path
)
return _allure_story
@property
def case_data_path(self):
"""返回 yaml 用例文件路径"""
return ensure_path_sep("/conf")
@property
def gen_file_name(self):
"""生成文件名 将.yaml替换成.py"""
# 例 /get_shop_info.yaml——>/get_shop_info.py
# 获取配置文件相对路径
l = len(self.case_data_path)
yaml_path = self.file_path[l:]
file_name = None
if '.yaml' in yaml_path:
file_name = yaml_path.replace('.yaml', '.py')
elif '.yml' in yaml_path:
file_name = yaml_path.replace('.yml', '.py')
return file_name
@property
def get_test_class_title(self):
"""自动生成类名"""
# 例 get_shop_info——>GetShopInfo
_file_name = os.path.split(self.gen_file_name)[1][:-3]
_name = _file_name.split("_")
_name_len = len(_name)
for i in range(_name_len):
_name[i] = _name[i].capitalize()
_class_name = "".join(_name)
return _class_name
@property
def get_func_title(self):
"""自动生成方法名"""
return os.path.split(self.gen_file_name)[1][:-3]
@property
def spilt_path(self):
# 使用"/"分割 获取文件名称
path = self.gen_file_name.split(os.sep)
path[-1] = path[-1].replace(path[-1], "test_" + path[-1])
return path
@property
def get_case_path(self):
"""生成测试用例目录"""
# 相对路径 test_case/x/test_get_shop_info.py
return ensure_path_sep("/test_case" + os.sep.join(self.spilt_path))
@property
def case_ids(self):
return [k for k in self.yaml_case_data.keys() if k != "case_common"]
@property
def get_file_name(self):
# 这里通过"/" 符号进行分割,提取出来文件名称
# 判断生成的 testcase 文件名称,需要以test_ 开头
case_name = self.spilt_path[-1].replace(
self.spilt_path[-1], "test_" + self.spilt_path[-1]
)
return case_name
def mk_dir(self) -> None:
""" 判断生成自动化代码的文件夹路径是否存在,如果不存在,则自动创建 """
# _LibDirPath = os.path.split(self.libPagePath(filePath))[0]
_case_dir_path = os.path.split(self.get_case_path)[0]
if not os.path.exists(_case_dir_path):
os.makedirs(_case_dir_path)
def get_case_automatic(self):
"""自动生成测试用例代码"""
# 获取配置文件下全部yaml文件
file_path = get_all_yaml_files(ensure_path_sep("/conf"), yaml_data_switch=True)
for file in file_path:
# 判断代理拦截的yaml文件,不生成test_case代码
if 'proxy_data.yaml' not in file:
# 获取配置yaml用例数据
self.yaml_case_data = YamlControl(file).read_yaml_data()
# yaml文件相对路径
self.file_path = file
# 判断用例需要用的文件夹路径是否存在,不存在则创建
self.mk_dir()
print(self.gen_file_name, "\n",
self.get_test_class_title,"\n",
self.get_func_title,"\n",
self.get_case_path,"\n",
self.case_ids,"\n",
self.get_file_name)
write_testcase_file(allure_epic = self.allure_epic,
allure_feature=self.allure_feature,
allure_story=self.allure_story,
class_title=self.get_test_class_title,
func_title=self.get_func_title,
case_path=self.get_case_path,
case_ids=self.case_ids,
file_name=self.get_file_name)
下一篇介绍用例内容写入/utils/write_testcase_file.py
,使用pytest实现自动化