您当前的位置: 首页 >  自动化

自在的旅者

暂无认证

  • 1浏览

    0关注

    695博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

基于数据驱动的接口自动化框架封装

自在的旅者 发布时间:2022-06-07 15:48:07 ,浏览量:1

1.数据驱动框架设计

1.框架结构

  • common: 这是一个package,主要用来存储所有的底层代码封装

  • logs: 这是一个目录,主要用来存放日志文件

  • report: 这是一个目录,里边的data表示测试结果数据,里边的html表示测试报告,注意这两个目录都是每次执行测试时自动生成的

  • testcases: 这是一个目录,主要用来存储excel文件,excel文件里是接口测试的相关数据

  • conftest.py: 重写pytest自带的一个内置函数的,统一管理自定义fixture的

  • pytest.ini: pytest相关的配置参数

  • run.py: 是整个框架执行的入口

2.excel数据规则设计

按照一定的维度进行分类,每个分类可以当做一个sheet工作表

  • 全局变量

    主要用来管理我们的公共数据

  • 接口默认参数

    通常在一个项目中,参数如果很多的时候,我们针对测试用例去传递数据就会很麻烦,所以我们针对每个接口的默认参数数据进行单独管理,在测试时只需要针对当前测试用例传递你要测试的某个字段值即可,其他字段统统来自于默认参数

    填写参数的规则:对于接口参数可能会有多种类型,表单的,查询的,json的,文件的等等

表单类型时:

{
    "data":{
        "xxx":"xxjsdhdh"
    }
}

查询参数:

{
    "params":{
        "xxx":"xxjsdhdh"
    }
}

json参数:

{
    "json":{
        "xxx":"xxjsdhdh"
    }
}

混合参数,比如既有表单又有查询:

{
    "params":{
        "xxx":"xxjsdhdh"
    },
    "data":{
     "ddd":"ddff"
    }
}

在这里插入图片描述

  • 测试集合管理

    测试集合管理 主要是为了控制要执行哪些测试集合,以及测试集合执行的顺序

    测试集合名称:对应的就是某个测试集合的sheet工作表名称

    是否执行:只有值是y时才会被执行,其他值不会被执行

在这里插入图片描述

  • 测试集合

每个测试集合在excel里是一个单独的sheet工作表,他负责某个模块或者某个接口相关的测试用例数据管理,一个测试集合中是可以存在多个测试用例的

  • 序号:仅仅只是个标识,没啥作用

  • 用例名称:一个用例可能会有多个接口的先后调用,在excel里一行数据就是针对一个接口的调用,多行数据就是多个接口的调用,如果一个用例需要用多行数据,那么这几行的用例名称保持一致

  • 接口名称:该列主要是为了和接口默认参数中的接口名称进行关联,通过接口名称得到该接口对应的默认参数,然后再根据测试数据来决定参数是什么

  • 接口地址:表示接口地址,在接口地址里域名几乎都是相同的,或者说是公共的,所以我们将域名作为了公共变量进行存储,那么在这里需要调用公共变量域名,调用方式${host},host就是公共变量中的一个变量

  • 请求方式:get/post/put/delete

  • 接口头信息:指的就是headers,对于一个接口来说不一定有特殊的头信息,那么就不填,如果有需要按照如下格式进行填写,以json格式字符串的方式:

  • token是要从登录接口的返回值中提取的,提取之后保存到一个变量中,咱们这里保存的变量名称叫做token,所以在这里引用了变量token,引用方式就是${token}

{
"Admin-Token":"${token}"
}

假如特殊的头信息有多个,写法就是在json字符串中继续追加键值对,比如:

{
"Admin-Token":"${token}",
"Content-Type":"application/json"
}
  • 测试数据:指的是在接口发起调用时传递的你要测试的某个数据,对于一个接口来说参数有很多,但是我们每次测试时,可能只是针对一两个参数进行测试,可以借助之前所学的通过jsonpath去匹配某些参数,并且替换他们的值

    设计思路:

    一个json格式的字符串,其中参数类型分为data、json、params、files

    其中的key是你要替换的目标参数对应的jsonpath,value就是该参数对应的新值,也就是测试数据

{
    "json":{
        "$.entity.customer_id":999999999,
    }
}

如果要替换多个参数:

{
    "json":{
        "$.entity.name":"自动化${{cur_timestamp()}}",
        "$.entity.num":"${timestamp}}"
    }
}
  • 响应提取:响应提取是为了从当前接口的返回值中提取某些信息,保存在变量中,以便后续接口要使用时进行变量引用,这也是我们常说的关联

比如每个接口都要用到token,token是登录接口产生的,所以登录的响应提取里要写提取内容,规则是以json格式的字符串作为标准格式,其中key是要保存的变量名称,value是要提取的参数对应的jsonpath表达式

{
    "token":"$.Admin-Token"
}

期望响应状态码:http响应状态码期望值

期望响应信息:表示我们要针对接口的响应信息中的某些参数进行断言,设计规则如下:

依然是json格式的字符串,最外层是一个列表,里边套的是多个字典,一个字典就是一个参数的断言。

每个字典的格式是必须包括两个键值对,一个actual表示实际值的key,实际值的value是参数对应的jsonpath表达式,一个expect表示期望值的key,期望值的value是期望内容

[
    {
    "actual":"$.code",
    "expect":500,
    },
    {
    "actual":"$.msg",
    "expect":"产品编号已存在,请校对后再添加!",
    }
]
2.数据驱动框架底层代码实现

1.创建项目 依赖于设计去创建项目结构

2.excel数据读取 在common这个package下创建一个python文件,叫做testcase_util.py

# !/usr/bin python3                                
# encoding: utf-8 -*-  
# @Copyright: 
import openpyxl
# 读取全局变量sheet工作表
def get_variables(wb):
    sheet_data = wb['全局变量']
    variables = {} # 用来存储读到的变量,名称是key,值是value
    lines_count = sheet_data.max_row # 获取总行数
    for l in range(2,lines_count+1):
        key = sheet_data.cell(l,1).value
        value = sheet_data.cell(l,2).value
        variables[key] = value
    return variables
def get_api_default_params(wb):
    sheet_data = wb['接口默认参数']
    api_default_params = {} # 用来存储读到的变量,名称是key,值是value
    lines_count = sheet_data.max_row # 获取总行数
    for l in range(2,lines_count+1):
        key = sheet_data.cell(l,1).value
        value = sheet_data.cell(l,2).value
        api_default_params[key] = value
    return api_default_params
# 获取要执行的测试集合名称
def get_casesuitename(wb):
    sheet_data = wb['测试集合管理']
    lines_count = sheet_data.max_row  # 获取总行数
    cases_suite_name = [] # 用来存储要执行的测试集合名称
    for l in range(2,lines_count+1):
        flag = sheet_data.cell(l,2).value
        if flag == 'y':
            suite_name = sheet_data.cell(l,1).value
            cases_suite_name.append(suite_name)
    return cases_suite_name
# 需要根据要执行的测试集合名称来读取对应的测试用例数据
def read_testcases(wb,suite_name):
    sheet_data = wb[suite_name]
    lines_count = sheet_data.max_row  # 获取总行数
    cols_count = sheet_data.max_column # 获取总列数
    """
    规定读出来的测试数据存储结构如下:
    {
        “新增客户正确”:[
            ['apiname','接口地址','请求方式','头信息',....],
            ['apiname','接口地址','请求方式','头信息',....],
        ],
        "新增客户失败-用户名为空":[
            ['apiname','接口地址','请求方式','头信息',....]
        ],
        "新增客户失败-手机号格式不正确":[
            ['apiname','接口地址','请求方式','头信息',....]
        ]
    }
    """
    cases_info = {} #用来存储当前测试集合中的所有用例信息的
    for l in range(2,lines_count+1):
        case_name = sheet_data.cell(l,2).value # 测试用例名称
        lines = [] # 用来存储当前行测试数据的
        for c in range(3,cols_count+1):
            cell = sheet_data.cell(l,c).value # 当前单元格数据
            if cell == None: # 处理空单元格
                cell = ''
            lines.append(cell)
        # 判断当前用例名称是否已存在于cases_info中
        # 如果不存在,那就是直接赋值
        # 否则就是在原来的基础上追加
        if case_name not in cases_info:
            cases_info[case_name] = [lines]
        else:
            cases_info[case_name].append(lines)
    return cases_info
# 整合所有要执行的测试用例数据,将其转成pytest参数化需要的数据结构格式
def get_all_testcases(wb):
    """
    整合后的数据结构是
    [
        ['新增客户接口测试集合','新增客户正确',[[],[]]],
        ['新增客户接口测试集合','新增客户失败-用户名为空',[[],[]]],
        ['新增客户接口测试集合','新增客户失败-手机号格式不正确',[[],[]]],
        ['新建产品接口测试集合','新建产品正确',[[],[]]],
        ['新建产品接口测试集合','新建产品失败-产品编码重复',[[],[]]],
    ]
    :param wb:
    :return:
    """
    test_data = [] # 用来存储所有测试数据
    # 获取所有要执行的测试集合名称
    cases_suite_name = get_casesuitename(wb)
    for suite_name in cases_suite_name:
        # 遍历读取每个要执行的测试集合sheet工作表中的测试用例数据
        cur_cases_info = read_testcases(wb,suite_name) # 是个字典
        for key,value in cur_cases_info.items():
            # key实际上就是测试用例名称,value实际上测试用例多行数据信息
            case_info = [suite_name,key,value]
            test_data.append(case_info)
    return test_data
if __name__ == '__main__':
    wb = openpyxl.load_workbook('../testcases/CRM系统接口测试用例.xlsx')
    # print(get_variables(wb))
    # print(get_api_default_params(wb))
    # print(get_casesuitename(wb))
    # print(read_testcases(wb,'新增客户接口测试集合'))
    print(get_all_testcases(wb))
3.接口调用底层方法封装

在common目录下创建一个client.py,写上如下代码

# !/usr/bin python3                                
# encoding: utf-8 -*-  

import jsonpath
import requests
session = requests.session()
class RequestsClient:
    def send(self,url,method,**kwargs):
        try:
            self.resp = session.request(url=url,method=method,**kwargs)
        except BaseException as e:
            raise BaseException(f'接口发起异常:{e}')
        return self.resp
    # 针对jsonpath的数据提取封装一个方法
    # 第一个参数指的是你要匹配的数据的jsonpath表达式
    # 第二个指的是你想返回匹配到的第几个,默认是0返回第一个
    def extract_resp(self,json_path,index=0):
        # 注意有的接口是没有返回信息的,返回信息是空的
        text = self.resp.text # 获取返回信息的字符串形式
        if text != '':
            resp_json = self.resp.json() # 获取响应信息的json格式
            # 如果能匹配到值,那么res就是个列表
            # 如果匹配不到res就是个False
            res = jsonpath.jsonpath(resp_json,json_path)
            if res:
                if index {md5(123456)}} 再比如
      
     
    {rdm_future_date_time(+60d)}}{{var_name}}}'            
关注
打赏
1665557745
查看更多评论
0.0447s