包括yaml和Excel用例测试和数据驱动开发。
数据驱动的自动化测试
什么是数据驱动
数据驱动是指将测试数据与测试代码分离,将测试数据存储在一个独立的文件中,然后在测试代码中读取测试数据,最后将测试数据作为参数传递给测试代码。这样做的好处是,测试数据和测试代码分离,测试数据可以独立于测试代码进行修改,测试代码可以独立于测试数据进行修改,测试数据可以被多个测试用例共享,测试数据可以被多个测试框架共享。
yaml数据驱动
yaml是一种数据序列化格式,可以用来存储数据,也可以用来存储配置信息。yaml的语法比较简单,可以用来存储简单的数据结构,比如列表、字典、字符串、数字等。
首先,在data文件夹下面创建所需要用到的测试数据文件,比如testlogin.yaml,然后在login_data.yaml文件中存储测试数据,比如:
#登录测试用例
# ---用来分割不同的测试用例
---
#测试用例名称
"case_name": "登录成功用例"
#url地址
"url": "/authorizations/"
#data
"data":
username: "python"
password: "12345678"
#期望结果
"expect": '"user_id": 1, "username": "python"'
---
#测试用例名称
"case_name": "登录失败用例"
#url地址
"url": "/authorizations/"
#data
"data":
username: "test123456"
password: "111111"
#期望结果
"expect": '"user_id": 1, "username": "python"'
在这个测试数据着哦功能,当输入用户名和密码正确时,登录成功,当输入用户名和密码错误时,登录失败。
接下来,在测试代码中读取测试数据,执行测试用例,然后将测试数据作为参数传递给测试代码(也即是参数化),比如:在testcases文件夹下面创建test_login.py文件,然后在test_login.py文件中编写测试代码.
这个测试代码应该包括以下内容:
- 获取测试用例内容,包括获取testlogin.yaml文件的文件路径,使用工具类来读取多个文档内容。
- 获取testlogin.yaml文件的文件路径:在config文件夹下面的Conf.py文件中添加获取testlogin.yaml文件的文件路径的方法,比如:
import os from utils.YamlUtil import YamlReader #1、获取项目基本目录 #获取当前项目的绝对路径 current = os.path.abspath(__file__) #print(current) BASE_DIR = os.path.dirname(os.path.dirname(current)) #定义data目录的路径 _data_path = BASE_DIR + os.sep + "data" # _开头的变量表示私有变量 def get_data_path(): return _data_path
- 获取testlogin.yaml文件的文件路径:在config文件夹下面的Conf.py文件中添加获取testlogin.yaml文件的文件路径的方法,比如:
- 参数化执行测试用例,使用pytest.mark.parametrize来实现参数化。
test_login.py文件代码如下:
from config import Conf
import os
from utils.YamlUtil import YamlReader
import pytest
from config.Conf import ConfigYaml
from utils.RequestsUtil import Request
#1、获取测试用例内容list
#获取testlogin.yml文件路径
test_file = os.path.join(Conf.get_data_path(),"testlogin.yml")
#print(test_file)
#使用工具类来读取多个文档内容
data_list = YamlReader(test_file).data_all()
print(data_list)
#2、参数化执行测试用例
@pytest.mark.parametrize("login",data_list)
def test_yaml(login):
#初始化url,data
url = ConfigYaml().get_conf_url()+login["url"]
print("url %s"%url)
data = login["data"]
print("data %s"%data)
#post请求
request = Request()
res = request.post(url,json=data)
#打印结果
print(res)
if __name__ == "__main__":
pytest.main(["-s","Test_login.py"])
到这里,我们已经完成了测试数据的编写,以及测试代码文档的编写,然后我们编写了使用登录的测试例,通过测试用例参数化去获取这个列表,最后我们还需要对得到的结果进行断言,断言的结果是否和我们期望的结果一致,如果一致,那么就是测试通过,如果不一致,那么就是测试失败。
Excel数据驱动开发
在上面的测试用例中,我们使用了yaml文件来存储测试数据,但是yaml文件的可读性不是很好,所以我们可以使用Excel来存储测试数据,然后使用python来读取Excel中的数据,然后再进行参数化。
这一节内容主要包括Excel用例设计,Excel读取以及Excel参数化运行等等。
Excel用例设计
EXCEL用例设计非常重要,要充分全面的覆盖到测试用例的各个方面,比如:测试用例编号、测试用例名称、测试用例描述、测试用例前置条件、测试用例步骤、测试用例预期结果、测试用例实际结果、测试用例执行结果等等。
Excel读取
在testcase文件夹下面创建文件夹t_excel,然后在t_excel文件夹下面创建文件excel_demo.py,然后在excel_demo.py文件中编写代码,代码如下:
在这里要注意xlrd读取excel文件的具体报错。
xlrd==1.2.0,报错信息如下:(在新版python3.10中,更新删除了getiterator方法,所以我们老版本的xlrd库调用getiterator方法时会报错。)
AttributeError: 'ElementTree' object has no attribute 'getiterator'
解决方法: 通过pip show xlrd命令,找出目录python\Lib\site-packages\xlrd下的xlsx.py文件
修改两个地方的的getiterator()改成iter(),下面的两个地方,这里已经把getiterator()改成iter()了
#1、导入包,xlrd
import xlrd
#2、创建workbook对象,这里先把excel文件拷贝一份到当前目录下
book = xlrd.open_workbook("testdata.xlsx")
#3、sheet对象
#索引
#sheet = book.sheet_by_index(0)
#名称
sheet = book.sheet_by_name("美多商城接口测试")
#4、获取行数和列数
rows = sheet.nrows #行数
cols = sheet.ncols #列数
#5、读取每行的内容
for r in range(rows):
r_values = sheet.row_values(r)
#print(r_values)
#6、读取每列的内容
for c in range(cols):
c_values = sheet.col_values(c)
#print(c_values)
#7、读取固定列的内容
print(sheet.cell(1,1))
Excel参数化运行
在utils文件夹下面创建ExcelUtil.py文件,然后在ExcelUtil.py文件中编写代码,主要用于参数化,代码如下:
import os
import xlrd
#目的:参数化,pytest 需要返回的数据用list来封装
#自定义异常
class SheetTypeError:
pass
#1、验证文件是否存在,存在读取,不存在报错
class ExcelReader:
def __init__(self,excel_file,sheet_by):
if os.path.exists(excel_file):
self.excel_file = excel_file
self.sheet_by = sheet_by
self._data=list()
else:
raise FileNotFoundError("文件不存在")
#2、读取sheet方式,名称,索引
def data(self):
#存在不读取,不存在读取
if not self._data:
workbook = xlrd.open_workbook(self.excel_file)
if type(self.sheet_by) not in [str,int]:
raise SheetTypeError("请输入Int or Str")
elif type(self.sheet_by) == int:
sheet = workbook.sheet_by_index(self.sheet_by)
elif type(self.sheet_by) == str:
sheet = workbook.sheet_by_name(self.sheet_by)
#3、读取sheet内容
#返回list,元素:字典
#格式[{"a":"a1","b":"b1"},{"a":"a2","b":"b2"}]
#1.获取首行的信息
title = sheet.row_values(0)
#2.遍历测试行,与首行组成dict,放在list
#1 循环,过滤首行,从1开始
for col in range(1,sheet.nrows):
col_value = sheet.row_values(col)
#2 与首组成字典,放list
self._data.append(dict(zip(title, col_value)))
#4、结果返回
return self._data
# head = ["a","b"]
# value1 = ["a1","b1"]
# value2 = ["a2","b2"]
# data_list= list()
# #zip
# data_list.append(dict(zip(head,value1)))
# data_list.append(dict(zip(head,value2)))
# #print(dict(zip(head,value1)))
# #print(dict(zip(head,value2)))
# print(data_list)
if __name__ == "__main__":
reader = ExcelReader("../data/testdata.xlsx","美多商城接口测试")
print(reader.data())
然后,获取是否运行,参数化,并进行结果断言。
获取是否运行
获取是否运行:在common文件夹下面创建ExcelData.py文件,然后在ExcelData.py文件中编写代码,代码如下:
from utils.ExcelUtil import ExcelReader
from common.ExcelConfig import DataConfig
class Data:
def __init__(self,testcase_file,sheet_name):
#1、使用excel工具类,获取结果list
#self.reader = ExcelReader("../data/testdata.xlsx","美多商城接口测试")
self.reader = ExcelReader(testcase_file,sheet_name)
#print(reader.data())
#2、列是否运行内容,y
def get_run_data(self):
"""
根据是否运行列==y,获取执行测试用例
:return:
"""
run_list = list()
for line in self.reader.data():
if str(line[DataConfig().is_run]).lower() == "y":
#print(line)
#3、保存要执行结果,放到新的列表。
run_list.append(line)
print(run_list)
return run_list
def get_case_list(self):
"""
获取全部测试用例
:return:
"""
# run_list=list()
# for line in self.reader.data():
# run_list.append(line)
run_list = [ line for line in self.reader.data()]
return run_list
def get_case_pre(self,pre):
#获取全部测试用例
#list判断,执行,获取
"""
根据前置条件:从全部测试用例取到测试用例
:param pre:
:return:
"""
run_list = self.get_case_list()
for line in run_list:
if pre in dict(line).values():
return line
return None
其中,我们这个是根据是否运行列==y,获取执行测试用例,还需要创建一个ExcelConfig.py文件,来表示对应的映射关系。代码如下:
#定义类
class DataConfig:
#定义列属性
#用例ID 模块 接口名称 请求URL 前置条件 请求类型 请求参数类型
#请求参数 预期结果 实际结果 备注 是否运行 headers cookies status_code 数据库验证
#用例ID
case_id = "用例ID"
case_model = "模块"
case_name = "接口名称"
url = "请求URL"
pre_exec = "前置条件"
method = "请求类型"
params_type = "请求参数类型"
params = "请求参数"
expect_result = "预期结果"
actual_result = "实际结果"
is_run = "是否运行"
headers = "headers"
cookies = "cookies"
code = "status_code"
db_verify = "数据库验证"
我们还需要获取testcase_file,sheet_name,所以我们需要修改config文件夹下面的config.yml,代码如下:
BASE:
test:
url: "http://211.103.136.242:8064"
case_file: "testdata.xlsx"
case_sheet: "美多商城接口测试"
改完之后,需要修改Conf.py文件,获取测试用例sheet名称,代码如下:
class ConfigYaml:
#定义方法获取需要信息
def get_excel_file(self):
"""
获取测试用例excel名称
:return:
"""
return self.config["BASE"]["test"]["case_file"]
def get_excel_sheet(self):
"""
获取测试用例sheet名称
:return:
"""
return self.config["BASE"]["test"]["case_sheet"]