Example #1
0
    def test_main(self, case_number, case_title, path, is_token, method,
                  parametric_key, file_var, file_path, parameters, dependent,
                  data, expect):
        """
        :param case_number: 用例编号
        :param case_title: 用例标题
        :param path: 接口路径
        :param is_token: token操作:写入token/读取token/不携带token
        :param method: 请求方式:get/post/put/delete....
        :param parametric_key: 入参关键字:params/data/json
        :param file_var: 接口中接受文件对象的参数名称
        :param file_path: 文件路径,单文件实例:/Users/zy7y/PycharmProjects/apiAutoTest/test/__init__.py
        多文件实例['/Users/zy7y/PycharmProjects/apiAutoTest/test/__init__.py','/Users/zy7y/PycharmProjects/apiAutoTest/test/test_api.py']

        :param parameters: path参数(携带在url中的参数)依赖处理 users/:id(id携带在url中) 实例:{"case_001": '$.data.id'},解析
        从用例编号为case_001的实际结果响应中提取data字典里面的id的内容(假设提取出来是500), 最后请求的路径将是host + users/500

        :param dependent: data数据依赖,该接口需要上一个接口返回的响应中的某个字段及内容:实例{"case_001",["$.data.id","$.data.username"]}
        解析: 从用例case_001的实际响应结果中提取到data下面的id,与username的值(假设id值为500,username为admin),那么提取的数据依赖内容将是{"id":500, "username":"******"}
        纳闷最终请求的data 将是 {"id":500, "username":"******"} 与本身的data合并后的内容
        :param data: 请求数据
        :param expect:预期结果,最后与config/config.yaml下的response_reg->response提取出来的实际响应内容做对比,实现断言
        :return:
        """

        # 感谢:https://www.cnblogs.com/yoyoketang/p/13386145.html,提供动态添加标题的实例代码
        # 动态添加标题
        allure.dynamic.title(case_title)

        logger.debug(f'⬇️⬇️⬇️...执行用例编号:{case_number}...⬇️⬇️⬇️️')
        with allure.step("处理相关数据依赖,header"):
            data, header, parameters_path_url = treat_data.treating_data(
                is_token, parameters, dependent, data, save_response_dict)
        with allure.step("发送请求,取得响应结果的json串"):
            res = br.base_requests(method=method,
                                   url=base_url + path + parameters_path_url,
                                   parametric_key=parametric_key,
                                   file_var=file_var,
                                   file_path=file_path,
                                   data=data,
                                   header=header)
        with allure.step("将响应结果的内容写入实际响应字典中"):
            save_response_dict.save_actual_response(case_key=case_number,
                                                    case_response=res)
            # 写token的接口必须是要正确无误能返回token的
            if is_token == '写':
                with allure.step("从登录后的响应中提取token到header中"):
                    treat_data.token_header[
                        'Authorization'] = jsonpath.jsonpath(res, token_reg)[0]
        with allure.step("根据配置文件的提取响应规则提取实际数据"):
            really = jsonpath.jsonpath(res, res_reg)[0]
        with allure.step("处理读取出来的预期结果响应"):
            expect = json.loads(expect)
        with allure.step("预期结果与实际响应进行断言操作"):
            assert really == expect
            logger.info(
                f'完整的json响应: {res}\n需要校验的数据字典: {really} 预期校验的数据字典: {expect} \n测试结果: {really == expect}'
            )
            logger.debug(f'⬆⬆⬆...用例编号:{case_number},执行完毕,日志查看...⬆⬆⬆\n\n️')
Example #2
0
    def get_data(self):
        """

        :return: data_list - pytest参数化可用的数据
        """
        data_list = []
        table = self.book.sheet_by_index(0)
        for norw in range(1, table.nrows):
            # 每行第4列 是否运行
            if table.cell_value(norw, 3) != '否':  # 每行第三列等于否将不读取内容
                value = table.row_values(norw)
                value.pop(3)
                # 配合将每一行转换成元组存储,迎合 pytest的参数化操作,如不需要可以注释掉 value = tuple(value)
                value = tuple(value)
                logger.info(f'{value}')
                data_list.append(value)
        return data_list
Example #3
0
    def get_data(self):
        """

        :return: data_list - pytest参数化可用的数据
        """
        data_list = []

        table = self.book.sheet_by_index(0)
        for norw in range(1, table.nrows):
            # 每行第4列 是否运行
            if table.cell_value(norw, 3) == '否':
                continue
            # 返回该行的所有单元格组成的数据 table.row_values(0) 0代表第1列
            case_number = table.cell_value(norw, 0)
            case_title = table.cell_value(norw, 1)
            path = table.cell_value(norw, 2)
            is_token = table.cell_value(norw, 4)
            method = table.cell_value(norw, 5)
            # 入参关键字
            parametric_key = table.cell_value(norw, 6)
            file_var = table.cell_value(norw, 7)
            file_path = table.cell_value(norw, 8)
            # 路径参数
            parameters = table.cell_value(norw, 9)
            dependent = table.cell_value(norw, 10)
            data = table.cell_value(norw, 11)
            expect = table.cell_value(norw, 12)
            value = [
                case_number, case_title, path, is_token, method,
                parametric_key, file_var, file_path, parameters, dependent,
                data, expect
            ]
            # 配合将每一行转换成元组存储,迎合 pytest的参数化操作,如不需要可以注释掉 value = tuple(value)
            value = tuple(value)
            logger.info(f'{value}')
            data_list.append(value)
        return data_list
Example #4
0
    def get_data(self):
        """
        :return: data_list - pytest参数化可用的数据
        """
        data_list = []
        table = self.book.sheet_by_index(0)  #打开excel中第一个sheet页  返回表格

        print(type(table))
        print(table.nrows)

        # table.nrows获取table里面行的数量,从0开始算
        for norw in range(1, table.nrows):  #行下标0123,这里抛去第一行文字说明
            # 每行第4列 是否运行
            if table.cell_value(norw,
                                3) == '否':  # 每行第三列 等于否 将不读取内容,列下标0123....
                continue  # 跳过这行,下一行第三个
            value = table.row_values(norw)  # 获取每行的所有值 是list
            value.pop(3)  # 删除列表中下标为3,即上面判断是否执行的单元格数据

            # 配合将每一行转换成元组存储,方便放入下面的大列表。迎合 pytest的参数化操作,如不需要可以注释掉 value = tuple(value)
            value = tuple(value)  #列表转元组
            logger.info(f'{value}')
            data_list.append(value)  #一行数据的元组 再放入大列表
        return data_list
Example #5
0
#!/usr/bin/env python
# -*- coding: utf-8 -*-

__author__ = 'Wenbin Wu <*****@*****.**>'
__credits__ = 'Python best'
__date__ = 'Tue Apr 19 10:38:48 2011'
__version__ = '0.1'

from test import logger
logger.info('test')


class TEST(object):
    """docstring for TEST"""
    def __init__(self):
        super(TEST, self).__init__()
        l = [('a', 'aa'), ('b', list()), ('c', None)]
        for x, y in l:
            setattr(self, x, y)

    def p(self):
        self.b.append('aaa')
        print locals()
        print self.a
        print self.b
        if self.c is None:
            print 'aaaa'


#t = TEST()
#t.p()
Example #6
0
    def treating_data(self, is_token, parameters, dependent, data,
                      save_response_dict):
        # 使用那个header
        if is_token == '':
            header = self.no_token_header
        else:
            header = self.token_header
        logger.info(f'处理依赖前data的数据:{data}')
        # 处理依赖数据data
        if dependent != '':
            if dependent.find('=') != -1:
                dependent_key = dependent.split('=')[0]
                dependent_value = dependent.split('=')[1]
                dependent_data = {
                    dependent_key:
                    save_response_dict.read_depend_data(dependent_value)
                }
            else:
                dependent_data = save_response_dict.read_depend_data(dependent)
            logger.debug(f'依赖数据解析获得的字典{dependent_data}')
            if data != '':
                data = json.loads(data)
                exists_key = False
                # 处理data与依赖中有相同key的问题, 目前之支持列表,字典,本地 列表形式调试通过,需要在定义时,data中该key定义成列表
                # 实例{"id": [1],"user":{"username":"******"}}
                for k, v in data.items():
                    for dk, dv in dependent_data.items():
                        if k == dk:
                            if isinstance(data[k], list):
                                data[k].append(dv)
                            if isinstance(data[k], dict):
                                data[k].update(dv)
                            exists_key = True
                if exists_key is False:
                    # 合并组成一个新的data
                    dependent_data.update(data)
                    data = dependent_data
                    logger.info(f'data有数据,依赖有数据时 {data}')

            else:
                # 赋值给data
                data = dependent_data
                logger.info(f'data无数据,依赖有数据时 {data}')
        else:
            if data == '':
                data = None
                logger.info(f'data无数据,依赖无数据时 {data}')
            else:
                data = json.loads(data)
                logger.info(f'data有数据,依赖无数据 {data}')

        # 处理路径参数Path的依赖
        # 传进来的参数类似 {"case_002":"$.data.id"}/item/{"case_002":"$.meta.status"},进行列表拆分
        path_list = parameters.split('/')
        # 获取列表长度迭代
        for i in range(len(path_list)):
            # 按着
            try:
                # 尝试序列化成dict:   json.loads('2') 可以转换成2
                path_dict = json.loads(path_list[i])
            except JSONDecodeError as e:
                # 序列化失败此path_list[i]的值不变化
                logger.error(f'无法转换字典,进入下一个检查,本轮值不发生变化:{path_list[i]},{e}')
                # 跳过进入下次循环
                continue
            else:
                # 解析该字典,获得用例编号,表达式
                logger.info(f'{path_dict}')
                # 处理json.loads('数字')正常序列化导致的AttributeError
                try:
                    for k, v in path_dict.items():
                        try:
                            # 尝试从对应的case实际响应提取某个字段内容
                            path_list[i] = jsonpath.jsonpath(
                                save_response_dict.actual_response[k], v)[0]
                        except TypeError as e:
                            logger.error(f'无法提取,请检查响应字典中是否支持该表达式,{e}')
                except AttributeError as e:
                    logger.error(
                        f'类型错误:{type(path_list[i])},本此将不转换值 {path_list[i]},{e}'
                    )
        # 字典中存在有不是str的元素:使用map 转换成全字符串的列表
        path_list = map(str, path_list)

        # 将字符串列表转换成字符:500/item/200
        parameters_path_url = "/".join(path_list)
        logger.info(f'path路径参数解析依赖后的路径为{parameters_path_url}')
        return data, header, parameters_path_url
Example #7
0
#!/usr/bin/env python
# -*- coding: utf-8 -*-

__author__  = 'Wenbin Wu <*****@*****.**>'
__credits__ = 'Python best'
__date__    = 'Tue Apr 19 10:38:48 2011'
__version__ = '0.1'

from test import logger
logger.info('test')

class TEST(object):
    """docstring for TEST"""
    def __init__(self):
        super(TEST, self).__init__()
        l = [('a', 'aa'), ('b',list()), ('c', None)]
        for x, y in l:
            setattr(self, x, y)
    def p(self):
        self.b.append('aaa')
        print locals()
        print self.a
        print self.b
        if self.c is None:
            print 'aaaa'
        
#t = TEST()
#t.p()
def test_var_args(farg, **args):
    x = args.get('abc', 'xxx')
    print x
Example #8
0
token_reg, res_reg = rc.read_response_reg()
case_data_path = rc.read_file_path('case_data')
report_data = rc.read_file_path('report_data')
report_generate = rc.read_file_path('report_generate')
log_path = rc.read_file_path('log_path')
report_zip = rc.read_file_path('report_zip')
email_setting = rc.read_email_setting()
# 实例化存响应的对象
save_response_dict = SaveResponse()
# 读取excel数据对象
data_list = ReadData(case_data_path).get_data()
# 数据处理对象
treat_data = TreatingData()
# 请求对象
br = BaseRequest()
logger.info(f'配置文件/excel数据/对象实例化,等前置条件处理完毕\n\n')


class TestApiAuto(object):
    # 启动方法
    def run_test(self):
        import os, shutil
        if os.path.exists('../report') and os.path.exists('../log'):
            shutil.rmtree(path='../report')
            shutil.rmtree(path='../log')
        # 日志存取路径
        logger.add(log_path, encoding='utf-8')
        pytest.main(args=[f'--alluredir={report_data}'])
        os.system(
            f'allure generate {report_data} -o {report_generate} --clean')
        logger.warning('报告已生成')
Example #9
0
    def treating_data(self, is_token, parameters, dependent, data, save_response_dict):
        #is_token 对应excel里面的token操作  空白 或者 读 写
        #parameters 对应url路径path参数依赖的内容
        #dependent 依赖数据的内容,元素表格中的jsonpath表达式
        #data   excel中  请求数据 内容,真正的data是请求+依赖
        #save_response_dict 保存实际响应的字典对象

        # 使用哪个header
        if is_token == '':
            header = self.no_token_header
        else:
            header = self.token_header
        logger.info(f'处理依赖前data的数据:{data}')

        # 处理依赖数据data  (请求数据的依赖)
        if dependent != '':
            #dependent两种形式
            #{"case_002": ["$.data.id"],"case_001":["$.meta.msg","$.meta.status"]}
            #key={"case_002": ["$.data.id"],"case_001":["$.meta.msg","$.meta.status"]}
            if dependent.find('=') != -1:  #存在上面的key= 形式,就把key和后面的分开保存为字典
                dependent_key = dependent.split('=')[0]
                dependent_value = dependent.split('=')[1]
                # dependent_data = {‘key’:{'id':1}}
                dependent_data = {dependent_key: save_response_dict.read_depend_data(dependent_value)}
            else:
                # {'id': 1}  dependent_data是最终值
                dependent_data = save_response_dict.read_depend_data(dependent)  # 直接保存
            logger.debug(f'依赖数据解析获得的字典{dependent_data}')


            if data != '':
                data = json.loads(data)#字符串转换为python对象,序列化

                exists_key = False  #不存在key就False,先默认为False,下面会具体判断有没有key
                # 处理data与依赖中有相同key的问题(原来请求就已经有name参数了,依赖里又从别的地方获取name参数), 目前支持列表,字典,本地 列表形式调试通过,需要在定义时,data中该key定义成列表
                # 实例{"id": [1],"user":{"username":"******"}}
                for k, v in data.items(): #data excel中 请求数据栏 的内容,只是请求数据
                    for dk, dv in dependent_data.items():  #这是请求的依赖数据字典
                        if k == dk:

                            #请求数据为{"id": [1], "user": {"username": "******"}},依赖数据为{"id": 500, "user": {"admin": "12345"}}
                            #data = {"id": [1,500], "user": {{"username": "******"},{"admin": "12345"}}
                            if isinstance(data[k], list):  #有相同的key,并且key的类型为列表(这里是按照原来的请求数据判断),就直接添加
                                data[k].append(dv)
                            if isinstance(data[k], dict):  #如果key对应的是字典,就更新
                                data[k].update(dv)
                            exists_key = True   # 如果修改了就改为存在

                if exists_key is False:  #不存在同样key,直接合并
                    #合并组成一个新的data  # dependent_data={'id':500}  data={'username':'******'}
                    # 最终data = {'id':500,'username':admin}
                    dependent_data.update(data)
                    data = dependent_data
                    logger.info(f'data有数据,依赖有数据时 {data}')

            else:
                # data为空直接把依赖赋值给data
                data = dependent_data
                logger.info(f'data无数据,依赖有数据时 {data}')
        else:  #依赖为空
            if data == '':
                data = None
                logger.info(f'data无数据,依赖无数据时 {data}')
            else:
                data = json.loads(data)   # 前面的依赖数据  已经在获取依赖数据的方法中python对象化了
                logger.info(f'data有数据,依赖无数据 {data}')

        # 处理路径参数Path的依赖 (url路径的依赖)   总结:分开放,先把能提取对应转换的变过来,变不了的保留,最后一起map列表字符串化
        # 传进来的参数类似 {"case_002":"$.data.id"}/item/{"case_002":"$.meta.status"},进行列表拆分
        path_list = parameters.split('/')  # {"case_002":"$.data.id"}  item  {"case_002":"$.meta.status"}
        # 获取列表长度迭代
        for i in range(len(path_list)):
            # 按着
            try:
                # 尝试序列化成dict:         中间的state或者数字2不能转换
                path_dict = json.loads(path_list[i])  #字符串转换为python对象,Python对象包括:所有Python基本数据类型,列表,元组,字典,自己定义的类,等等等等
            except JSONDecodeError as e:
                # 序列化失败此path_list[i]的值不变化
                logger.error(f'无法转换字典,进入下一个检查,本轮值不发生变化:{path_list[i]},{e}') #json.loads('2'),转换不了先保存下面会再处理
                # 跳过进入下次循环
                continue
            else:
                # 解析该字典,获得用例编号,表达式
                logger.info(f'{path_dict}')   # 打印第一次转换成果,已经转换成功的放进来

                # 处理json.loads('数字')正常序列化导致的AttributeError  为什么不直接map化呢???(先把能依赖的依赖了)
                try:
                    for k, v in path_dict.items():
                        #{'case_002':'$.data.id'}      case_002   .   $.data.id
                        try:
                            # 尝试从对应的case实际响应提取某个字段内容{'id':500} , $.data.id   根据key从实际响应中提取value
                            path_list[i] = jsonpath.jsonpath(save_response_dict.actual_response[k], v)[0]
                            # 500   path_list[i]是最终地址
                        except TypeError as e:
                            logger.error(f'无法提取,请检查响应字典中是否支持该表达式,{e}')  # 类似找不到这种状态
                except AttributeError as e:

                    logger.error(f'类型错误:{type(path_list[i])},本此将不转换值 {path_list[i]},{e}')
        # 字典中存在有不是str的元素:使用map 转换成全字符串的列表     #path_list = [500,'item',200]
        path_list = map(str, path_list)
        #path_list = ['500','item','200']

        # 将字符串列表转换成字符:500/item/200
        parameters_path_url = "/".join(path_list)  #相当于部分路径
        logger.info(f'path路径参数解析依赖后的路径为{parameters_path_url}')
        return data, header, parameters_path_url