栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

进阶之路--从0开始学接口测试(11)--业务流接口自动化(投资接口)

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

进阶之路--从0开始学接口测试(11)--业务流接口自动化(投资接口)

业务流测试(各种功能) 对应的是单接口测试

业务流本质上还是接口关联,需要多个接口一起测试,并且完成业务流程,即同时完成多个接口的测试,观察业务流程是否成功,也是一次集成测试.

方法1:

直接把要关联的接口封装到APICase里,然后填入访问接口时所需要的参数,每次执行用例的时候调用一次,从关联接口中获得测试接口所需要的数据,测试用例执行的只是被测接口

优点:简单易懂

缺点:如果业务流需要多个接口,就要封装多个访问接口的函数,并且多次调用,代码变得繁琐

方法2:

不需要封装访问关联接口的函数,把测试需要关联接口数据都写在excel表格中,每次执行测试用例方法时候会一一访问不同的接口,获取返回结果中的对应数据,得到下一个接口所需要的参数,测试用例执行的是所有关联接口和被测接口

优点:代码变得简洁,方法都经过封装放入一个类中,而且关联接口比较多的时候,不需要一一封装和调用,直接通过测试用例函数进行访问,只需要从响应结果里获取其他接口需要的数据即可

缺点:难度较大,逻辑较复杂,调试不方便,可以通过日志观察

 

封装正则表达式替换数据的函数

-在APICase类里定义实例方法/类方法

  @classmethod
    def replace_data(cls,string):
        # 给指定的字符串替换成动态数据
        result = re.finditer("#(.*?)#", string)
        for el in result:
            old = el.group()
            prop_name = el.group(1)
            string = string.replace(old, str(getattr(cls, prop_name)))
        return string

定义需要替换的数据名称,获得替换数据

参数填入需要替换的字符串,还需要准备的数据有替换的内容,内容可以从配置文件获取,作为前置条件,在开始执行测试用例函数之前获取(需要替换的数据名称要跟excel表格里面标记的##对应数据名称一致)

访问登录接口,需要有账号和密码,审核接口需要管理员操作.所以需要获得投资人和借款人还有管理员的账号和密码,我们把投资人和借款人设定为同一个人

@ddt
class TestInvest(unittest.TestCase,APICase):
    @classmethod
    def setUpClass(cls) -> None:
        cls.investor_phone = secret_config.investor["mobile_phone"]
        cls.investor_pwd = secret_config.investor["pwd"]
        cls.loan_phone = secret_config.user["mobile_phone"]
        cls.loan_pwd = secret_config.user["pwd"]
        cls.admin_phone = secret_config.admin_user["mobile_phone"]
        cls.admin_pwd = secret_config.admin_user["pwd"]

注意:这里设置的替换方法为实例方法,所以获得需要替换的数据可以定义为类属性,也可以是实例属性

如果替换数据定义为实例属性,而替换方法为类方法的话,类方法里就不能获取实例属性,导致不能替换成功

使用替换数据函数,进行动态数据替换(数据预处理)
 @data(*info)
    def test_invest(self,case_info):
        #获取需要替换的数据
        headers = case_info["headers"]
        json_data = case_info["json"]
        #正则表达式动态替换数据里面带#号的元素
        headers = self.replace_data(headers)
        json_data = self.replace_data(json_data)

        headers = json.loads(headers)
        json_data = json.loads(json_data)
        expected = json.loads(case_info["expected"])

正则表达式方法的应用:

首先要获取需要替换的数据(字符串)

需要类里定义跟#标记的同名属性(从配置文件获得,通过接口响应结果获得)

使用替换函数,需要进行两次替换(因为headers和json_data分别是2个不同的字符串)

最后把替换的数据转化成字典

访问接口,获得响应结果
       #获取响应结果
        resp = requests.request(method=case_info["method"],
                                       url = host+case_info["url"],
                                       headers = case_info["headers"],
                                       json = case_info["json"]).json()

*数据提取(extractor)

如果在编写测试用例时候,发现下一个接口需要的参数是从其他接口获得,就要从前面接口获取响应结果中的指定数据,设置成跟#里同名的属性,作为下一个接口访问时候需要的参数

在excel表格中添加title extractor,里面填入每次访问接口之后提取需要作为后面接口参数的响应数据,相当于方法1用函数访问接口,然后设置类属性

 

字典的key作为要设置属性的属性名,由字典的value作为模糊查询的表达式

通过jsonpath在响应数据中模糊查询得到相应的值作为类的属性值,然后通过动态设置类属性,得到类属性

首先要判断extractor里是否有内容

        #数据提取
        #判断extractor里面是否有数据,这个过程可以放到数据预处理阶段
        if case_info["extractor"]:
            #反序列化转换成字典
            extractor = json.loads(case_info["extractor"])

        #下面设置属性的过程要放在访问接口之后
        #还需要判断一次extractor是否存在,才能进行遍历
        if case_info["extractor"]:
            for key,value in case_info["extractor"].items():
                    #动态设置类属性
                    # 字典的key为类属性名,
                    # 由字典的value作为模糊查询的表达式,通过jsonpath在响应数据中模糊查询得到相应的值作为类的属性值
                setattr(APICase,key,jsonpath(resp,value)[0])

通过反序列化把里面的内容转换为字典后,再遍历字典

通过setattr动态设置属性,把key作为属性名,通过由value的jsonpath表达式查询到的响应结果作为属性值,得到类属性

设置成类属性是因为,需要用到该属性值的是之后的接口,实例能调用类属性

断言

 for key, value in case_info["expected"].items():
            self.assertEqual(value, resp[key])

完整流程

代码优化(封装)

1,数据预处理封装

定义好函数的名称-prev_data(case_info),需要返回替换后的case_info(字典)

    def prev_data(self,case_info):
        """数据预处理,完成替换,转化为字典"""
        # 获取需要替换的数据
        headers = case_info["headers"]
        json_data = case_info["json"]

        # 正则表达式动态替换数据里面带#号的元素
        headers = self.replace_data(headers)
        if "#over_amount#" in json_data:
            json_data = json_data.replace("#over_amount#", str(self.leave_amount + 1))
            json_data = json_data.replace("#member_id#", str(self.member_id))
        else:
            json_data = self.replace_data(json_data)
        if case_info["extractor"]:
            extractor = case_info["extractor"]
            case_info["extractor"] = json.loads(extractor)
        #修改原先字典的value
        case_info["headers"] = json.loads(headers)
        case_info["json"] = json.loads(json_data)
        case_info["expected"] = json.loads(case_info["expected"])

        return case_info

*这里有一个单独对#over_amount#的字符串进行单独处理,是因为在提现接口中,其中有一天用例是余额不足的用例,余额不足需要提现的金额为#leave_amount#(余额)+1,但是读取excel的json的值是一个字符串 不能执行+1这个运算,所以这条用例需要手工提取出来进行+1

转换前字典case_info键为json和headers的值是字符串,经过数据替换,并且把值转换成字典,再通过对case_info重新赋值的方法,

得到的结果是字典嵌套字典{“json”: {"mobile_phone": "15100002222", "pwd": "12345678"}}

2,访问接口封装

定义函数的名称visit(case_info) 注意,这里的case_info 是通过数据预处理方法函数得出的返回值,也就是重新赋值后的case_info

    def visit(self,case_info):
        """访问接口"""
        # 参数是数据预处理后得到的返回结果,重新赋值后的case_info
        resp = requests.request(method=case_info["method"],
                                url=host + case_info["url"],
                                headers=case_info["headers"],
                                json=case_info["json"]).json()

 3,数据提取封装

定义函数的名称extract(case_info,resp),这里的case_info也是通过数据预处理函数得到的返回值

    def extract(self,case_info,resp):
        """响应结果数据提取"""
        #需要判断一次extractor是否存在, 才能进行遍历
        if case_info["extractor"]:
            for key, value in case_info["extractor"].items():
                # 动态设置类属性
                # 字典的key为类属性名,
                # 由字典的value作为模糊查询的表达式,通过jsonpath在响应数据中模糊查询得到相应的值作为类的属性值
                setattr(APICase, key, jsonpath(resp, value)[0])

因为extractor从第五个用例开始有None的值,所以需要判断是否存在数据

也可以把这个方法设置成类方法

4,断言(可以不用封装)

定义函数的名称assert_all(case_info,resp),这里的case_info也是通过数据预处理函数得到的返回值

    def assert_all(self,case_info,resp):
        """断言"""
        for key, value in case_info["expected"].items():
            self.assertEqual(value, resp[key])

整体结果

 

5,封装全部(装*用)

定义函数名称steps(case_info),表示测试的步骤,包含之前封装的4个方法

    def steps(self,case_info):
        """测试步骤"""
        case_info = self.prev_data(case_info)
        resp = self.visit(case_info)
        self.extract(case_info, resp)
        self.assert_all(case_info, resp)

最后剩下1行代码

 装*就要撞到极致

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/450937.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号