Python接口自动化实战(第二阶段)- 数据与代码分离

摘要:
接口模块案例_名称:

前面我们已经实现了用unittest框架编写测试用例,实现了请求接口的封装,这样虽然已经可以完成接口的自动化测试,但是其复用性并不高。

我们看到每个方法(测试用例)的代码几乎是一模一样的,试想一下,在我们的测试场景中,一个注册接口有可能会有十几条到几十条测试用例,如果每组数据都编写一个方法,这样将会有更多的重复项代码,不仅执行效率不高,也不好维护。

接下来将会对框架进行优化,采用数据驱动方式,1)把测试数据用excel表格管理起来,代码做封装,2)用ddt来驱动测试,两部分相互独立。

1.数据与代码分离:excel管理测试数据

在上一节的代码中, test_register.py 模块中,定义了三个方法(三个测试用例),每一个测试用例都需要提供一组测试数据:url,params,method,expect_res等,不利于修改和构建,现在我们新建 excel文件(TestData.xlsx )。如下:

自动化用例设计:

关于自动化测试用例的设计,是基于对接口业务流程的熟悉,只有熟悉业务流程,才能设计出较好的自动化测试数据。这边要考虑的点很多,

  • id:用例编号,从1开始,唯一
  • module:接口模块
  • case_name:用例名称
  • method:请求类型
  • url:接口地址信息
  • params:请求参数

Python接口自动化实战(第二阶段)- 数据与代码分离第1张

用例设计好了,这边我遇到了三个问题:

第一:如何读取测试数据?

第二:读取的测试数据,应该存储成什么格式?

第三:数据如何传递?

当然,用例的设计对于越复杂的场景,考虑的就会越多,其中有一点很重要,尽量保持用例的独立性,用例之间的关联性不要太强,避免一条用例的失败,导致其他用例也无法执行。

xlrd 使用 

安装xlrd第三方库,pip install xlrd.from xlrd import open_workbook

wb = open_workbook("TestData.xlsx")  # 打开excel
sh = wb.sheet_by_name("register")  # 定位工作表
print(sh.row_values(0))   # 输出第1行的所有值(列表格式)
print(dict(zip(sh.row_values(0),sh.row_values(1))))  # 将数据和标题组成字
for i in range(sh.nrows): print(sh.row_values(i))

 封装读取excel操作 -如何读取测试数据?

实现代码如下:

from xlrd import open_workbook
class Doexcel():

    def excel_data_list(self, filename, sheetname):
        data_list = []
        wb = open_workbook(filename)  # 打开excel
        sh = wb.sheet_by_name(sheetname)  # 定位工作表
        header = sh.row_values(0)   # 获取标题行的数据
        for i in range(1, sh.nrows):   # 跳过标题行,从第二行开始获取数据
            col_datas = dict(zip(sh.row_values(0), sh.row_values(i)))   # 将标题和每一行的数据,组装成字典
            data_list.append(col_datas)   # 将字典添加到列表中 ,列表嵌套字典,相当于每个字典的元素都是一个列表(也就是一行数据)
        return data_list

    def get_test_data(self, data_list, case_id):
        '''
        :param data_list: 工作表的所有行数据
        :param case_id: 用例id,用来判断执行哪几条case。如果id=all ,那就执行所有用例;否则,执行列表参数中指定的用例
        :return:  返回最终要执行的测试用例
        '''
        if case_id == 'all':    
            final_data = data_list
        else:
            final_data = []
            for item in data_list:
                if item['id'] in case_id:
                    final_data.append(item)
        return final_data

if __name__ == '__main__':
data_list=Doexcel().excel_data_list('F:JialiProgramfileserviceX_API_TestTest_datasTestData.xlsx','register')
final_data=Doexcel().get_test_data(data_list, [1,2,3])
print(final_data)

执行结果

[{'method': 'post', 'expect_res': 200.0, 'actual_res': '', 'id': 1.0, 'test_res': '', 'case_name': 'test_register_normal', 'url': 'http://27.154.55.14:8180/api/fcb2bcrm/webRegister', 'module': 'register', 'params': '{"LoginAccount":"test01@gamil.com","Password":"123456","Type":"Pro"}'}, 
{'method': 'post', 'expect_res': 400.0, 'actual_res': '', 'id': 2.0, 'test_res': '', 'case_name': 'test_register_existing', 'url': 'http://27.154.55.14:8180/api/fcb2bcrm/webRegister', 'module': 'register', 'params': '{"LoginAccount":"test01@gamil.com","Password":"123456","Type":"Pro"}'},
{'method': 'post', 'expect_res': 400.0, 'actual_res': '', 'id': 3.0, 'test_res': '', 'case_name': 'test_register_invalid_email', 'url': 'http://27.154.55.14:8180/api/fcb2bcrm/webRegister', 'module': 'register', 'params': '{"LoginAccount":"test01@gamil","Password":"123456","Type":"Pro"}'}]

2.ddt 数据驱动- 如果传递数据?

数据驱动,个人理解就是测试数据的参数化

1)安装第三方库 : pip install ddt

2)引入ddt模块:from ddt import ddt,data 

3)test_register.py 代码加入ddt

# 导入
import unittest
import requests
from Common.http_request import HttpRequest
from ddt import ddt,data   # 引入ddt模块
from Common.do_excel import *

test_data = Doexcel().excel_data_list('F:JialiProgramfileserviceX_API_TestTest_datasTestData.xlsx','register')   #读取工作表 register 的所有数据 ,返回的是个列表嵌套字典格式

@ddt
class TestRegister (unittest.TestCase):   # 类必须以Test开头,继承TestCase

    def setUp(self):
        print("======开始执行测试用例======")

    def tearDown(self):
        print("======测试用例执行完毕======")

    # 测试用例
    @data(*test_data)   
    def test_register(self, data_itme):  # data_item 就是每一组测试数据(字典的形式)
        # 发送请求
        res = HttpRequest().http_request(data_itme['url'],eval(data_itme['params']),data_itme['method'])
        # 断言:
        try:
            self.assertEqual(int(data_itme['expect_res']), res.status_code)
        except AssertionError as e:
            print('Failed')
            raise e   # 注意一定要抛出异常

3.测试结果写回 - 扩展doExcel类

在excel表格中,有 两列的值是需要在执行完测试用例后写回的:实际结果和测试结果。

    def write_back_result(self, filename, sheetname, row, actual_res, test_result):
        '''
        
        :param filename: 文件名
        :param sheetname: 要写回数据的表格
        :param row: 要写回的行数
        :param actual_res: 实际结果 :实际结果是第8列,测试结果是第9列 ,比如:(2,8)(2,9)
        :param test_result: 测试结果 :pass/failed
        :return: 
        '''
        wb = load_workbook(filename)
        sheet = wb[sheetname]
        sheet.cell(row,8).value = actual_res    
        sheet.cell(row,9).value = test_result 
        wb.save(filename)

在test_register.py文件中,每次执行完一组测试数据,调用 write_back_result()方法,将所需要的参数传递进去。

Python接口自动化实战(第二阶段)- 数据与代码分离第2张

 

免责声明:文章转载自《Python接口自动化实战(第二阶段)- 数据与代码分离》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇jQuery Pagination Ajax分页插件中文详解(摘)xmldocument操作下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

CSS 颜色相关

CSS预定义颜色表示法(就是使用颜色的英文): color:red; color:green; color:blue; CSS RGB颜色表示法: color:rgb(255,0,0); color:rgb(0,255,0); color:rgb(0,0,255); RGB颜色表示法就是红(R:red),绿(G:green),蓝(B:blue),这三原色混...

执行计划--Adhoc和Prepare

在和SQLPass讨论adhoc和Prepare时,有各自不同的观点,我来发表下我的理解,不对之处,敬请指出! Adhoc(即席查询):没有参数化的查询计划会被标记为adhoc,adhoc不能理解为该执行计划不会被重用。 Prepared(预定义):查询中使用到参数的执行计划会被标记为Prepared. 在后续测试中,每次测试之前需要清除执行计划: --清...

layui中radio的动态加载(进入修改页面时,设置radio)

动态设置   radio  的值让它处于选中状态 效果图 : 前端代码: <div class="layui-form-item"> <label class="layui-form-label">状态</label> <div class="layui-input-block">...

LVM原理及实现过程

这里引用鸟哥说明 LVM 的重点在於『可以弹性的调整 filesystem 的容量!』而并非在於效能与数据保全上面。 需要文件的读写效能或者是数据的可靠性,请参考前面的 RAID 小节。 LVM 可以整合多个实体 partition 在一起, 让这些 partitions 看起来就像是一个磁碟一样!而且,还可以在未来新增或移除其他的实体 partition...

vue列表页进入详情页,返回列表项不刷新

功能 像搜索功能,在点击某项进入详情页,再回到搜索界面,如果不做特殊处理,初始化到原来的状态,在vue中可以使用keep-alive缓存搜索界面,达到数据不刷新的结果。 思路 在搜索路由对象的meta添加一个keepAlive属性,值为true,表示在路由切换的时候,会被缓存。这样一来搜索界面的数据不会被初始化。 缓存界面 keepAlive如果为true...

Axios 各种请求方式传递参数格式

为方便起见,为所有支持的请求方法提供了别名 在使用别名方法时, url、method、data 这些属性都不必在配置中指定 axios.request(config) axios.get(url[, config]) axios.delete(url[, config]) axios.head(url[, config]) axios.post(ur...