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:请求参数

 

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

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

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

第三:数据如何传递?

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

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:\JialiProgramfile\serviceX_API_Test\Test_datas\TestData.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:\JialiProgramfile\serviceX_API_Test\Test_datas\TestData.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()方法,将所需要的参数传递进去。

 

 

 

 

 

posted @ 2019-03-16 12:33  carrie_lin  阅读(2360)  评论(0编辑  收藏  举报