• 全网最牛,Python接口自动化测试实战干货-项目接口案例,看这篇足够...



    前言

    1、单元测试主要做什么?

    测试发现:从多个文件里面去找到我们的测试用例;
    测试执行:按照一定的顺序和规则去执行,并生成结果;
    测试判断:通过断言判断预期结果和实际结果的差异;
    测试报告:统计测试进度,耗时,通过率,生成测试报告;

    单元测试框架只是自动化测试框架中的组成部分之一。

    自动化测试框架中还包括:设计模式、数据驱动、关键字驱动、全局配置文件的封装、日志监控、selenium和requests二次封装、断言、报告邮件…

    2、pytest中的装饰器@pytest.mark.parametrize()的基础用法

    所有的测试框架都离不开数据驱动,那数据驱动是什么?

    数据驱动:其实就是把我们测试用例的数据放到excel、yaml、csv、mysql。然后通过去改变数据到改变测试用例的执行结果。

    @pytest.mark.parametrize(args_name,args_value)
    
    • 1

    args_name:参数的名称
    args_value:参数的值(支持格式:列表、元组,字典列表、字段元组,即:[]、()、[{},{},{}]、({},{},{})),值的注意的是,参数的值有多少个,这个方法就被执行多少次。

    pytest默认的测试用例规则:(可以根据pytest.ini配置文件进行修改)

    模块名必须以test_或者_test开头;
    类名必须以Test开头;
    方法名必须以test开头;

    使用的方式:

    方式1:最基本的用法

    import pytest
    
    class TestApi:
    
        @pytest.mark.parametrize('args', ['张三', '李四', '王五', '赵六'])
        def test_01_api(self, args):
            print(args)
    
    if __name__ == '__main__':
        pytest.main(['-vs', 'test_api.py'])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    执行以上代码,test_01_api用例会执行四次,分别将’张三’, ‘李四’, ‘王五’, '赵六’打印出来。-vs指令参数表示打印出较为详细的日志信息。test_api.py表示执行的文件。

    执行结果:

    在这里插入图片描述

    方式2:解包的用法

    若我们将传入参数的格式进行变化,如下图所示,参数的值写成两个list,测试用例就会执行两次,而这两次分别传入两个list。

    在这里插入图片描述

    现在我们传入两个参数名称,如下图所示,观察运行结果会发现,每一个list中的第一个元素会传给name,第二个元素会传给age,这就是解包的用法,此方法与unittest框架中实现数据驱动的装饰器ddt类似。

    在这里插入图片描述

    import pytest
    
    class TestApi:
    
        @pytest.mark.parametrize('name,age', [['张三', 20], ['王五', 21]])
        def test_01_api(self, name, age):
            print(name, age)
            
    if __name__ == '__main__':
        pytest.main(['-vs', 'test_api.py'])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    3、Pytest结合yaml实现数据驱动

    1)yaml简介

    yaml它是一个数据文件保存的一个数据格式,支持注释、换行、裸字符串(最小单位的数据)

    2)yaml用途

    用于全局配置文件:环境、数据库信息、账号信息、日志格式、报告名称。
    用于接口自动化里面多一些复杂的多接口串联。
    用于编写接口测试用例

    3)yaml语法规则

    区分大小写
    和Python一样也是通过缩进的方式来表示层级关系
    和缩进多少层无关,只和左边是否对齐有关系
    #表示注释

    4)yaml数据组成举例

    map对象:键(空格)值

    在这里插入图片描述

    数组(列表):用一组横线开头

    在这里插入图片描述

    用来验证yaml文件格式或者json文件格式是否正确的网站:https://www.bejson.com/

    数据驱动实战:

    新建一个yaml文件data.yaml,编写代码如下:

    在这里插入图片描述

    -
      api_name: 获取网易新闻
      api_request:
        url: https://api.apiopen.top/getWangYiNews
        method: post
        headers:
          Content-Type: application/json
        params:
          page: 1
          count: 5
      api_validate:
        - eq: {code: 200}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    新建一个Python文件yaml_util.py,封装读取yaml文件数据的函数。

    在这里插入图片描述

    import yaml
    
    # 读取yaml文件内容的函数
    def read_yaml():
    
        with open('data.yaml', encoding='utf_8', mode='r') as f:
            data = yaml.load(f, Loader=yaml.FullLoader)
            return data
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    新建一个Python文件test_api.py编写测试用例

    import pytest
    import requests
    from pytest_yaml.yaml_util import read_yam
    
    class TestApi:
    
        @pytest.mark.parametrize('args', read_yaml())
        def test_01_api(self, args):
            url = args['api_request']['url']
            method = args['api_request']['method']
            headers = args['api_request']['headers']
            params = args['api_request']['params']
    
            if method == 'get':
                requests.get(url)
            else:
                resp = requests.post(url, json=params, headers= headers)
                print(resp.json())
    
    if __name__ == '__main__':
        pytest.main(['-vs', 'test_api.py'])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    运行结果:

    在这里插入图片描述

    添加断言

    在这里插入图片描述

    如上图所示,获取yaml文件中断言的数据列表,所有多个断言,采用for循环遍历,使用assert方法进行断言,运行之后成功。

    以上所实现的接口测试是最基础的,采用了一个接口,执行一个测试用例,只有一次断言。若在实际工作中使用,这远远是不够的。

    4、接口实战

    1)获取token鉴权码接口

    使用微信开放文档中获取Access token接口进行练习,接口文档为:

    在这里插入图片描述

    由接口文档可知,方法为Get,接口地址为:api.weixin.qq.com/cgi-bin/tok… ,接口需要传入的参数为grant_type、appid、secret。

    使用Python访问该接口,将响应的值打印到控制台,如下所示:

    在这里插入图片描述

    import unittest
    import requests
    
    class TestApi(unittest.TestCase):
        def test_01_get_token(self):
            url = " https://api.weixin.qq.com/cgi-bin/token"
            params = {
                "grant_type": "client_credential",
                "appid": "xxxxxxxxxxxxx",
                "secret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
            }
            resp = requests.get(url, params=params)
            print(resp.json())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    添加断言:

    断言返回的状态码是否为200

    self.assertEqual(resp.status_code, 200)
    
    • 1

    断言返回的结果中是否包含access_token

    self.assertIn('access_token', resp.text)
    
    • 1

    断言返回的结果中expires_in的值是否等于7200

    self.assertEqual(dict_result['expires_in'], 7200)
    
    • 1

    反序列化
    把json格式的字符串转化为字典格式dict_result = json.loads(resp.text)
    直接将响应的内容获取为字典格式dict_result = resp.json()

    import json
    import unittest
    import requests
    
    
    class TestApi(unittest.TestCase):
        def test_01_get_token(self):
            url = " https://api.weixin.qq.com/cgi-bin/token"
            params = {
                "grant_type": "client_credential",
                "appid": "xxxxxxxxxxxxx",
                "secret": "xxxxxxxxxxxxxxxxxxx"
            }
            resp = requests.get(url, params=params)
            print(resp.text, type(resp.text))
    
            # 方法一:反序列化,把json格式的字符串转化为字典格式
            dict_result = json.loads(resp.text)
            
            # 方法二:直接将响应的内容获取为字典格式
            # dict_result = resp.json()
    
            # 断言
            # 断言返回的状态码是否为200
            self.assertEqual(resp.status_code, 200)      # 状态断言
            # 断言返回的结果中是否包含access_token
            self.assertIn('access_token', resp.text)     # 业务断言1
            # 断言返回的结果中expires_in的值是否等于7200
            self.assertEqual(dict_result['expires_in'], 7200)    #  业务断言2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    2)获取公众号已创建的标签

    接口文档如下:

    在这里插入图片描述

    import unittest
    import requests
    
    
    class TestApi(unittest.TestCase):
        # 定义一个全局变量、类变量
        access_token = ""
    
        # 获取access_token
        def test_01_get_token(self):
            url = " https://api.weixin.qq.com/cgi-bin/token"
            params = {
                "grant_type": "client_credential",
                "appid": "wx5046a51617ff683a",
                "secret": "334c600a9fbbcadac918d5665d7b1d12"
            }
            resp = requests.get(url, params=params)
            print(resp.text, type(resp.text))
    
            # 反序列化,把json格式的字符串转化为字典格式
            dict_result = resp.json()
            # 获取鉴权码access_token并保存
            TestApi.access_token = dict_result['access_token']
            # 断言
            # 断言返回的状态码是否为200
            self.assertEqual(resp.status_code, 200)      # 状态断言
            # 断言返回的结果中是否包含access_token
            self.assertIn('access_token', resp.text)     # 业务断言1
            # 断言返回的结果中expires_in的值是否等于7200
            self.assertEqual(dict_result['expires_in'], 7200)    #  业务断言2
    
        # 获取公众号已创建的标签
        def test_02_select_flag(self):
            url = "  https://api.weixin.qq.com/cgi-bin/tags/get"
            params = {
                "access_token": TestApi.access_token
            }
            resp = requests.get(url, params=params)
            print(resp.json())
    
            # 断言返回的状态码是否为200
            self.assertEqual(resp.status_code, 200)  # 状态断言
            # 断言返回的结果中是否包含tags
            self.assertIn('tags', resp.text)  # 业务断言
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    3)接口关联

    以上接口文档可知,接口2的执行需要传入接口1中返回的access_token,那么,如何实现access_token的关联呢?

    定义一个全局变量access_token = “”;

    在接口1响应内容中获取access_token的值并保存到全局变量中TestApi.access_token = dict_result[‘access_token’]

    将全局变量access_token作为参数传入接口2中 “access_token”: TestApi.access_token

    可将全局变量获取之后保存在yaml文件中。

    5、Cookie、session、Token鉴权解决方案

    什么是cookie?
    cookie是在服务器产生的存储在客户端的一小段文本信息。格式是字典,键值对。

    cookie的分类:
    会话级:保存内存,当浏览器关闭就会消失。
    持久化:保存硬盘,只有当失效时间到了才会被清除。

    如何查看cookie?

    在这里插入图片描述

    cookie如何实现鉴权(原理)

    当客户第一次访问服务器时,那么服务器就会产生cookie,然后通过响应头的方式在set-cookie里面传输到客户端,客户端从第2-N次请求都会自动的带上这些cookie。

    致命的弱点:cookie保存在客户端,对于一些敏感的信息,比如用户名、密码、身份证号这些信息都不安全。

    用python实现一个登录接口,并从响应中提取token。

    接口为post请求,参数和响应结果如下所示:

    在这里插入图片描述

    在这里插入图片描述

    用python发送请求,代码如下:

    import requests
    import unittest
    import json
    
    class TestApi(unittest.TestCase):
    
        def test_01_api(self):
    
            url = "http://api-store**************staff/login"
    
            jsontext = {
                "account": "188********",
                "password": "123456"
            }
            data = {
                "device_type": 30,
                "system": 2,
                "jsonText": json.dumps(jsontext)
            }
    
            headers = {
                "Content-Type": "application/x-www-form-urlencoded"
            }
    
            resp = requests.post(url, data=data, json=json,headers=headers)
            print(resp.text)
    
    
    if __name__ == '__main__':
        unittest.main()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    执行结果如下:

    在这里插入图片描述

    通过正则表达式取出token的值

    # 通过正则表达式提取token的值
    value = re.search('"token":"(.+?)"', resp.text)
    print(value.group(1))
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    将获取的token保存到全局变量中

    import re
    import requests
    import unittest
    import json
    
    
    class TestApi(unittest.TestCase):
    
        # 定义一个全局变量
        token = ""
    
        def test_01_api(self):
    
            url = "http://api***********/login"
    
            jsontext = {
                "account": "188******",
                "password": "123456"
            }
            data = {
                "device_type": 30,
                "system": 2,
                "jsonText": json.dumps(jsontext)
            }
    
            headers = {
                "Content-Type": "application/x-www-form-urlencoded"
            }
    
            resp = requests.post(url, data=data, json=json,headers=headers)
            print(resp.text)
    
            # 通过正则表达式提取token的值
            value = re.search('"token":"(.+?)"', resp.text)
    
            # 将提取的token值保存为一个全局变量
            TestApi.token = value.group(1)
    
            # 后面需要用到token的操作可以直接使用全局变量
            print(TestApi.token)
    
    
    if __name__ == '__main__':
        unittest.main()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    如果在下个接口测试的时候我们需要传入cookies,那么我们就可以定义一个保存cookies的全局变量test_cookies = “”。

    通过test_cookies = resp.cookies提取cookies并保存到全局变量test_cookies中,在下面接口测试中将cookies传入,即:requests.post(url, data=data, json=json,
    headers=headers, cookies=test_cookies),这样就实现了Cookie的鉴权。

    session鉴权:

    当用户第一次访问服务器的时候,然后在服务器端会保存一个sessionid,这个sessionid是经过加密的,然后通过cookie把这个sessionid保存到客户端,在请求服务器的时候只发送sessionid。

    class TestApi(unittest.TestCase):
    
        # 定义一个全局变量
        session = ""
    
        def test_01_api(self):
    
            url = "http://**********"
            TestApi.session = requests.Session()
            # 请求的时候发送sessionid
            res = TestApi.session.get(url=url)
            print(TestApi.session)
            print(res.json())
    
            
    if __name__ == '__main__':
        unittest.main()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    session鉴权的致命弱点:

    对于浏览器来说sessionid是非常好用的,只需要在cookie中存一个字符串就行了,但是服务器必须存储所有在线的用户sessionid,那么同时在线的人数越多开销越大,严重影响了服务器的性能。当用户量特别大的时候,会导致服务器崩溃。

    token鉴权:

    上述的解决方案都是围绕session,那么能不能不用sessionid来解决呢?

    如果不适用sessionid,如何确保数据是服务器生成的呢?怎么去验证呢?用户信息存在哪?

    于是有人想到了自己按照一定规则生成加密字符串,服务器只验证不存储,只要验证通过说明是自己生成的,用户信息存储在加密字符串中,这样性能、CORS(跨域资源共享)都能解决,而这个加密字符串就是token。

    当一个用户登录之后,就给他发送一个token令牌,下一次用户再次请求的时候只需要带上这个令牌。

    token的加密方式:
    对称加密:DES AES
    双钥加密:RSA
    只加密不解密:MD5 SHA

    token的分类:
    access_token:有时间限制,限制在15分钟
    refresh_token:一般15天

    cookie,session,token的相同点和区别:

    相同点:
    都是用于做鉴权的,都是服务器产生的。

    区别:
    cookie存储在客户端,session存储在服务器,session的安全性比cookie高。所以一般情况下把重要的信息放到session,把不重要的放在cookie。

    session存在服务器内存,token存在服务器的文件或者数据库中,token的好处是比session更节省服务器资源,token只需要在服务器解密即可。

    在技术不断进步的过程中,以上逐渐无法满足用户的需求,出现了新的问题:第三方支付、银行、金融项目,对于安全性的要求更高,于是就出现了接口签名sign。

    下面是我整理的2023年最全的软件测试工程师学习知识架构体系图

    一、Python编程入门到精通

    请添加图片描述

    二、接口自动化项目实战

    请添加图片描述

    三、Web自动化项目实战

    请添加图片描述

    四、App自动化项目实战

    请添加图片描述

    五、一线大厂简历

    请添加图片描述

    六、测试开发DevOps体系

    请添加图片描述

    七、常用自动化测试工具

    请添加图片描述

    八、JMeter性能测试

    请添加图片描述

    九、总结(尾部小惊喜)

    风雨兼程,唯有坚持不懈,方能登上成功之巅。披荆斩棘,勇往直前,梦想的光芒终将照亮前行的道路。相信自己,你必将创造奇迹。

    只要心怀勇气,坚持不懈,你一定能够克服困难,实现自己的梦想。每一步努力都是通向成功的阶梯,坚信自己,勇往直前。

    一路风雨,一路阳光,坚持不懈,勇往直前,你终将收获辉煌。每一份努力,都是未来成功的种子,在坚持中开花结果,相信自己,你能创造奇迹。

  • 相关阅读:
    eeglab加载显示脑电数据,eeglab简单操作
    网络编程 day1
    [linux] 过滤警告⚠️
    基于java+SpringBoot+HTML+Mysql在线学习答疑平台(类似百度知道)
    华为云发布拉美互联网战略,携手客户与伙伴迈向云原生2.0新时代
    HTTP请求和响应(补充HTTP协议)
    HTTP响应详解
    恒生电子笔试题
    RT-DETR优化改进:轻量级Backbone改进 | VanillaNet极简神经网络模型 | 华为诺亚2023
    python pyinstaller库
  • 原文地址:https://blog.csdn.net/csdnchengxi/article/details/134266611