Yaml数据驱动
1.本文浅浅介绍一下我是如何实现读取yaml文件的。
- a.首先介绍一下yaml的结构类型:
对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
纯量(scalars):单个的、不可再分的值 - b.语法法则:大小写敏感、使用缩进表示层级关系、缩进时不允许使用Tab键,只允许使用空格、缩进的空格数不重要,只要相同层级的元素左侧对齐即可
2.在自动化测试过程中我们可能会使用到yaml文件来实现数据驱动。在这里我将介绍yaml文件结合csv文件实现的数据驱动。
3.自动化测试过程中,一个接口会存在多组测试用例,这时候我们就需要用到数据驱动来实现。yaml文件中的"-"就代表一项测试用例参数。由此可知,以下文件包含了两项测试用例,一个是登录成功、一个是登录失败。
# yaml文件中的测试用例
-
name: 登录成功
request:
method: get
url: /open/auth/Token
data:
app_key: 123456
project_code: 123456
method: 123456
validate: True
code: 0
-
name: 登录失败
request:
method: get
url: /open/auth/Token
data:
app_key:
project_code: 123456
method: 123456
validate: True
code: 0
4.有了yaml文件我们就可以读取了:读取方法一
import yaml
BASE_PATH = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
# 入参yaml_name是要读取的yaml文件的名字
def read_testcases_yaml(yaml_name):
# 得到yaml文件存放的位置
data_file_path = os.path.join(BASE_PATH, "data")
# 将文件路径进行拼接并打开文件
with open(data_file_path + '/testdata/' + yaml_name, mode='r', encoding='utf-8') as f:
# 使用yaml.load方法进行读取
value = yaml.load(stream=f, Loader=yaml.FullLoader)
return value
c.yaml文件读取方法二:由于我们的yaml文件中一个用例的参数可能大致上一致,不一致的只是value。所以当用例很多的时候我们就要重复的写很多次key、value。这里我们结合csv文件来优化一下。
- yaml文件:
-
name: $csv{name}
request:
method: get
url: /open/auth/Token
data:
app_key: $csv{app_key}
project_code: 123456
method: 123456
validate: $csv{validate}
boole: $csv{boole}
code: 0
- csv文件:
name,app_key,validate,boole
登录成功,123456,0,True
登录失败,,2006,False
- 在这里我们同样需要读取yaml文件:
# 入参filename是要读取的yaml文件的名字
def read_yaml(filename, read_csv=True):
"""
读取接口测试用例数据
:param filename: 用例数据.yaml文件名
:param read_csv: 是否读取csv文件,默认为True
:return: 用例数据字典
"""
# read_csv为True则读取对于csv文件,动态解析test_file中的变量
filename = BASE_PATH + '/data/testdata/' + filename
if read_csv:
# 定义一个列表
csv_list = []
# 打开csv文件,这里由于我的csv文件名与yaml文件名一致所以替换后缀即可
with open(filename.replace('yaml', 'csv'), 'r', encoding='utf-8') as f:
# csv库提供了能直接将csv文件读取为字典的函数:DictReader()
reader = csv.DictReader(f)
for row in reader:
# 创建一个字典
csv_list.append(dict(row))
# contextlib.ExitStack()管理多个上下文管理器
with ExitStack() as stack:
# 创建上下文管理器
above_context = stack.enter_context(open(filename, 'r+', encoding='utf-8'))
# 这是yaml列表中的每一项数据
above_context_lines = above_context.readlines()
# 定义一个列表
ret = []
# csv_list的长度即为动态解析后的测试用例数量
for i in range(0, len(csv_list)):
testcase = ''
# 遍历列表字符串列表是否存在字符串形如$csv{...}
# new_line 是yaml文件一项数据的每一行
for new_line in above_context_lines:
# print("new line", new_line)
if re.search(r".+\$csv{(.+)}", new_line):
# group(0) 是获取取得的字符串整体,group(1)是取出括号⾥⾯我们要匹配的内容
temp_name = re.search(r".+\$csv{(.+)}", new_line).group(1)
temp_value = re.search(r".+:(.+)", new_line).group(1)
new_line = new_line.replace(temp_value.strip(), csv_list[i][temp_name])
testcase += new_line
# 把string转换成流的yaml工具包读取成列表
f = io.StringIO(testcase)
value = yaml.load(f, yaml.FullLoader)
ret.append(value[0])
logger.debug("{}全部写入完成".format(ret))
return ret
else:
# 读原yaml文件数据并返回
return read_testcases_yaml(filename)
- 读取到之后我们使用@pytest.mark.parametrize()获取参数。我们的断言和参数获取都可以进行进一步的封装,我这里是没有封装的。
# 调用read_yaml方法,方法返回结果给到'case_info'
@pytest.mark.parametrize('case_info', read_yaml('get_token.yaml'))
# base_url是项目路径我写在了.ini文件中,可以在这里直接使用
def test_get_token(self, case_info, base_url):
# 由于参数是字典所以可以通过Key来获取value
method = case_info['request']['method']
url = base_url + case_info['request']['url']
data = case_info['request']['data']
# res 响应结果
# 我这里的request已经简单封装好了
res = RequestUtil().send_request(method, url, data)
try:
# 断言
assert case_info['code'] == res.json()['code']
- request的封装
import json
import requests
# 封装就意味着,这个方法要能够使用所有的请求
class RequestUtil:
# 全局变量,类变量,通过类名调用
sess = requests.session()
def send_request(self, method, url, datas=None, **kwargs):
# 将method参数转为小写字母的字符串类型
method = str(method).lower()
# 自定义变量res
res = None
if method == "get":
res = RequestUtil.sess.request(method=method, url=url, params=datas, **kwargs)
elif method == "post":
# datas参数不为空,将datas参数装完Json格式
if datas:
datas = json.dumps(datas)
res = RequestUtil.sess.request(method=method, url=url, data=datas, **kwargs)
elif method == "put":
print("内容")
elif method == "delete":
print("内容")
else:
pass
# 返回发送请求成功后的响应结果
return res
到这里简单的yaml文件的读取就结束啦,由于我也是刚刚接触所以写的不好,有不对的地方还请多多指教呀~