Python接口自动化浅析数据驱动原理
作者:软件测试自动化测试 发布时间:2022-02-22 21:52:01
在上一篇Python接口自动化测试系列文章:Python接口自动化浅析登录接口测试实战,主要介绍接口概念、接口用例设计及登录接口测试实战。
以下主要介绍使用openpyxl模块操作excel及结合ddt实现数据驱动。
在此之前,我们已经实现了用unittest框架编写测试用例,实现了请求接口的封装,这样虽然已经可以完成接口的自动化测试,但是其复用性并不高。
我们看到每个方法(测试用例)的代码几乎是一模一样的,试想一下,在我们的测试场景中,
一个登录接口有可能会有十几条到几十条测试用例,如果每组数据都编写一个方法,
这样将会有更多的重复项代码,不仅执行效率不高,也不好维护。
接下来将会对框架进行优化,采用数据驱动方式:
把测试数据用excel表格管理起来,代码做封装;
用ddt来驱动测试,两部分相互独立。
一、openpyxl模块
openpyxl模块介绍
openpyxl是python第三方模块,运用openpyxl库可以进行excel的读和写。
在了解openpyxl模块之前,我们需要先熟悉excel的结构,才能更好理解openpyxl是如何操作excel。
从外到内,首先是一个excel文件(名),打开excel之后,会看到底部有一个或多个sheet(工作簿),每个sheet里有很多单元格,总体来说,主要分为三个层级。
在opnepyxl里面,一个Excel文件对应着一个Workbook对象, 一个Sheet对应着一个Worksheet对象,而一个单元格对应着一个Cell对象。了解这些之后,对openpyxl是如何操作excel就比较清楚了。
openpyxl安装
pip install openpyxl
openpyxl简单使用
import openpyxl
if __name__ == '__main__':
path = 'F:/case/test_case.xlsx'
# 读取excel文件
workbook = openpyxl.load_workbook(path)
# 读取所有sheet
sheet = workbook.get_sheet_names()
# 获取某个sheet
sheet = workbook[sheet[0]]
# 获取某个cell的值
cell_val = sheet.cell(row=2, column=2).value
print(cell_val)
以上仅介绍openpyxl常用的语法,有兴趣了解更多内容可自行百度扩展。
二、Excel用例管理
在项目下,新建一个文件夹:data,文件夹下新建一个cases.xlsx文件,用来存放测试用例。
以下,是一个简单的登录测试用例设计模板:
可以根据该表格生成实际结果,并将测试结果写入(Pass、Fail)表格。
公众号后台回复:接口测试用例模板,可以获取完整接口测试用例Excle模板。
既然有了用例模板,我们就开始从用openpyxl模块对excel读写数据。
如下,在common文件夹下,新建excel_handle.py,用于封装操作excel的类。
excel_handle.py
import openpyxl
class ExcelHandler:
def __init__(self, file):
self.file = file
def open_excel(self, sheet_name):
"""打开Excel、获取sheet"""
wb = openpyxl.load_workbook(self.file)
# 获取sheet_name
sheet = wb[sheet_name]
return sheet
def get_header(self, sheet_name):
"""获取header(表头)"""
wb = self.open_excel(sheet_name)
header = []
# 遍历第一行
for i in wb[1]:
# 将遍历出来的表头字段加入列表
header.append(i.value)
return header
def read_excel(self, sheet_name):
"""读取所有数据"""
sheet = self.open_excel(sheet_name)
rows = list(sheet.rows)
data = []
# 遍历从第二行开始的每一行数据
for row in rows[1:]:
row_data = []
# 遍历每一行的每个单元格
for cell in row:
row_data.append(cell.value)
# 通过zip函数将两个列表合并成字典
data_dict = dict(zip(self.get_header(sheet_name),row_data))
data.append(data_dict)
return data
@staticmethod
def write_excel(file, sheet_name, row, cloumn,data):
"""Excel写入数据"""
wb = openpyxl.load_workbook(file)
sheet = wb[sheet_name]
sheet.cell(row, cloumn).value = data
wb.save(file)
wb.close()
if __name__ == "__main__":
# 以下为测试代码
excel = ExcelHandler('../data/cases.xlsx')
data = excel.read_excel('login')
接下来结合ddt实现数据驱动,先简单来介绍下ddt。
三、ddt介绍及使用
ddt介绍
名称:Data-Driven Tests,数据驱动测试
作用:由外部数据集合来驱动测试用例的执行
核心的思想:数据和测试代码分离
应用场景:一组外部数据来执行相同的操作
优点:当测试数据发生大量变化的情况下,测试代码可以保持不变
实际项目:excel存储测试数据,ddt读取测试数据到单元测试框架(测试用例中)
补充:
所谓数据驱动,就是数据的改变从而驱动自动化测试的执行,最终引起测试结果的改变。说的直白些,就是参数化的应用。
ddt安装
pip install ddt
ddt使用
要想知道ddt到底怎么使用,我们从ddt模块源码中提取出三个重要的函数ddt、unpack、data。
def ddt(cls):
"""
Class decorator for subclasses of ``unittest.TestCase``.
Apply this decorator to the test case class, and then
decorate test methods with ``@data``.
For each method decorated with ``@data``, this will effectively create as
many methods as data items are passed as parameters to ``@data``.
The names of the test methods follow the pattern
``original_test_name_{ordinal}_{data}``. ``ordinal`` is the position of the
data argument, starting with 1.
For data we use a string representation of the data value converted into a
valid python identifier. If ``data.__name__`` exists, we use that instead.
For each method decorated with ``@file_data('test_data.json')``, the
decorator will try to load the test_data.json file located relative
to the python file containing the method that is decorated. It will,
for each ``test_name`` key create as many methods in the list of values
from the ``data`` key.
"""
for name, func in list(cls.__dict__.items()):
if hasattr(func, DATA_ATTR):
for i, v in enumerate(getattr(func, DATA_ATTR)):
test_name = mk_test_name(name, getattr(v, "__name__", v), i)
test_data_docstring = _get_test_data_docstring(func, v)
if hasattr(func, UNPACK_ATTR):
if isinstance(v, tuple) or isinstance(v, list):
add_test(
cls,
test_name,
test_data_docstring,
func,
*v
)
else:
# unpack dictionary
add_test(
cls,
test_name,
test_data_docstring,
func,
**v
)
else:
add_test(cls, test_name, test_data_docstring, func, v)
delattr(cls, name)
elif hasattr(func, FILE_ATTR):
file_attr = getattr(func, FILE_ATTR)
process_file_data(cls, name, func, file_attr)
delattr(cls, name)
return cls
def unpack(func):
"""
Method decorator to add unpack feature.
"""
setattr(func, UNPACK_ATTR, True)
return func
def data(*values):
"""
Method decorator to add to your test methods.
Should be added to methods of instances of ``unittest.TestCase``.
"""
global index_len
index_len = len(str(len(values)))
return idata(values)
ddt:
装饰类,也就是继承自TestCase的类。
data:
装饰测试方法。参数是一系列的值。
unpack:
传递的是复杂的数据结构时使用。比如使用元组或者列表,添加unpack之后,ddt会自动把元组或者列表对应到多个参数上,字典也可以这样处理;当没有加unpack时,方法的参数只能填一个。
知道了具体应用后,简单来个小例子加深理解。
test_ddt.py
import unittest
import ddt
# 装饰类
@ddt.ddt
class DdtDemo(unittest.TestCase):
def setUp(self):
pass
def tearDown(self):
pass
# 装饰方法
@ddt.data(("15312344578", "12345678"), ("15387654321", "12345678"))
@ddt.unpack
def test_ddt(self, username,password):
print(username,password)
if __name__ == '__main__':
unittest.main(verbosity=2)
运行结果为:
Ran 2 tests in 0.001s
OK
15312344578 12345678
15387654321 12345678
上面的例子是为了加深理解,接下来介绍excel结合ddt实现数据驱动,优化之前的test_login.py模块。
test_login.py
import unittest
from common.requests_handler import RequestsHandler
from common.excel_handler import ExcelHandler
import ddt
import json
@ddt.ddt
class TestLogin(unittest.TestCase):
# 读取excel中的数据
excel = ExcelHandler('../data/cases.xlsx')
case_data = excel.read_excel('login')
print(case_data)
def setUp(self):
# 请求类实例化
self.req = RequestsHandler()
def tearDown(self):
# 关闭session管理器
self.req.close_session()
@ddt.data(*case_data)
def test_login_success(self,items):
# 请求接口
res = self.req.visit(method=items['method'],url=items['url'],json=json.loads(items['payload']),
headers=json.loads(items['headers']))
try:
# 断言:预期结果与实际结果对比
self.assertEqual(res['code'], items['expected_result'])
result = 'Pass'
except AssertionError as e:
result = 'Fail'
raise e
finally:
# 将响应的状态码,写到excel的第9列,即写入返回的状态码
TestLogin.excel.write_excel("../data/cases.xlsx", 'login', items['case_id'] + 1, 9, res['code'])
# 如果断言成功,则在第10行(测试结果)写入Pass,否则,写入Fail
TestLogin.excel.write_excel("../data/cases.xlsx", 'login', items['case_id'] + 1, 10, result)
if __name__ == '__main__':
unittest.main()
整体流程如下图:
来源:https://blog.csdn.net/ZangKang1/article/details/119488376


猜你喜欢
- 一、椭圆绘制实例代码:import tkinter as tk &nb
- 在SQL Server中,如果我想授予一个用户klb拥有创建表的权限,但是我又不想授予其数据库角色db_ddladmin,因为这样会扩大其权
- 本文主要介绍Python3.9的一些新特性,如:更快速的进程释放,性能的提升,简便的新字符串函数,字典并集运算符以及更兼容稳定的内部API,
- 大家好哈,上一节我们研究了一下爬虫的异常处理问题,那么接下来我们一起来看一下Cookie的使用。为什么要使用Cookie呢?Cookie,指
- 实际工作经历中,免不了有时候需要连接数据库进行问题排查分析的场景,之前一直习惯通过 mysql -uxxx -hxxxx -P1234 ..
- 一、函数解释在torch/_C/_VariableFunctions.py的有该定义,意义就是实现一下公式:换句话说,就是需要传入5个参数,
- 1、numpy.array() 可以把列表转换为矩阵numpy.array(object, dtype=None, *,
- 一、Excel环境配置 服务器端的环境配置从参考资料上看,微软系列的配置应该都行,即:1.Win9x+PWS+Office2.Wi
- 本文旨在给大家提供一种构建一个完整 UI 库脚手架的思路:包括如何快速并优雅地构建UI库的主页、如何托管主页、如何编写脚本提升自己的开发效率
- abs(number) 返回绝对值。 array(arglist) 创建一个数组。 asc(string) 返回字符串第一个字符的ansi码
- 前言当你逐渐了解tushare之后,你会发现我们要进行数据分析只靠tushare是不够的,接下来我将介绍如何利用第三方软件将tushare获
- 我就废话不多说了,大家还是直接看代码吧!import pymysql,hashlib结果:单条结果 {'id': 1,
- 功能介绍 (需要版本5.0.45)大数据操作ORM性能瓶颈在实体转换上面,并且不能使用常规的Sql去实现当列越多转换越慢,SqlSugar将
- 一、线程编程(Thread)1、线程基本概念1.1、什么事线程线程被称为轻量级的进程线程也可以使用计算机多核资源,是多任务编程方式线程是系统
- python文件特定行插入和替换实例详解python提供了read,write,但和很多语言类似似乎没有提供insert。当然真要提供的话,
- 数据共享是数据库最基本的特征之一。但是数据共享虽然为员工带来了便利,但也产生了一些负面作用。例如因用户并发存取而导致的对数据一致性的破坏、由
- 在框架选择上,不少人会觉得swoft才是最强PHP框架,尤其是在常驻内存模式的应用级高性能框架,性能是这一堆页面级框架遥不可及的,但是使用上
- Python文件遍历os.walk()与os.listdir()在图片处理过程中,样本数据的组织是个常见的问题,样本组织好了,后面数据转换、
- 前言字符集是一套符号和编码的规则,不论是在oracle数据库还是在mysql数据库,都存在字符集的选择问题,而且如果在数据库创建阶段没有正确
- 本文实例为大家分享了python通过输入联系人首字母查询联系人的具体代码,供大家参考,具体内容如下# -*- coding:utf-8 -*