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里有很多单元格,总体来说,主要分为三个层级。

Python接口自动化浅析数据驱动原理

在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文件,用来存放测试用例。

Python接口自动化浅析数据驱动原理

以下,是一个简单的登录测试用例设计模板:

Python接口自动化浅析数据驱动原理

可以根据该表格生成实际结果,并将测试结果写入(Pass、Fail)表格。

公众号后台回复:接口测试用例模板,可以获取完整接口测试用例Excle模板。

既然有了用例模板,我们就开始从用openpyxl模块对excel读写数据。

如下,在common文件夹下,新建excel_handle.py,用于封装操作excel的类。

Python接口自动化浅析数据驱动原理

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()

整体流程如下图:

Python接口自动化浅析数据驱动原理

来源:https://blog.csdn.net/ZangKang1/article/details/119488376

标签:Python,接口自动化,数据驱动
0
投稿

猜你喜欢

  • python读取查看npz/npy文件数据以及数据完全显示方法实例

    2022-05-15 15:45:36
  • 在python中使用正则表达式查找可嵌套字符串组

    2021-10-07 07:02:06
  • python logging模块的使用详解

    2023-06-08 08:43:34
  • 支付宝lab logo设计创意发想

    2009-11-12 12:44:00
  • python使用matplotlib绘图时图例显示问题的解决

    2022-11-13 16:59:47
  • 交互因视觉设计而更完美

    2008-05-31 17:22:00
  • 对跨多个表格的数据组合时需要用到的SQL

    2009-01-06 11:18:00
  • 老版本PHP转义Json里的特殊字符的函数

    2023-11-06 02:32:18
  • 专家教你安装 MySQL的与MySQL GUI Tools

    2012-01-29 17:59:05
  • Python标准库使用OrderedDict类的实例讲解

    2022-07-17 22:27:31
  • 如何编写python的daemon程序

    2023-07-27 05:13:28
  • django模板语法学习之include示例详解

    2023-10-03 18:52:54
  • 基于python图像处理API的使用示例

    2022-12-19 02:14:53
  • 儿童编程python入门

    2021-03-12 15:25:06
  • 揭开HTML 5工作草稿的神秘面纱

    2008-02-13 08:25:00
  • MySQL中SQL的单字节注入与宽字节注入

    2009-03-25 14:49:00
  • 优化 MySQL 语句的十个建议

    2012-05-08 07:14:36
  • python应用之如何使用Python发送通知到微信

    2022-03-04 01:59:55
  • 如何在Python中将字符串转换为集合

    2023-08-26 07:31:11
  • 深入理解Python3 内置函数大全

    2022-06-27 22:11:36
  • asp之家 网络编程 m.aspxhome.com