• 【Pytest 基于pytest+yaml+request+热加载+allure的框架封装 03】


    一、接口自动化测试框架基于pytest+yaml数据驱动

    1、@pytest.mark.parametrize(args_name,args_value)    -->实现数据驱动的一个装置器

    什么意思呢?把这段代码放到用例上面,然后通过args_name来获取yaml的参数,传递给具体的用例

    • args_name:参数名
    • args_value:参数值(list,tuple,字典列表,字典元祖),有多少个值用例就会执行多少次
      • 例如:[a,b,c] (a,b,c)执行3次,[{a:1},{b:1}]执行2次,({a:1},{b:1})执行2次

    2、yaml有两种数据类型

    键值对:key:value  如:'name':'赵丽颖'   ,读取之后是字典如:{'name':'赵丽颖'}。

    列表:通过-表示一组值。如:-name1:赵丽颖,-name2:倪妮   读取之后是字典列表:[{'name':'赵丽颖'},{'name':'倪妮'},{}'name':'高圆圆']

    3、操作yaml文件需要安装

    pip3 install pyyaml

    #案例:实现单接口的自动化测试(多参数)

    思路:testcases文件夹放具体的接口,yaml放测试用例参数,写一个工具类yaml_util读取yaml的文件,pytest.ini写运行方式。

    1、get_paraments.yaml文件   -->可以放到一个专门存放yaml文件类目下(比如:paraments)

    - name: 归因查询正常用例
      request:
        method: post
        url: http://tkio-receive.solar-engine.com/receive/query/attribution
        params:
          appkey: 55705dbd45dd246751b87bba94b8c73c
          device_id: c3381276ae145b3663c8e0f6dd9f628a
          device_id_type: idfa
        validate: None
    - name: appkey为空
      request:
        method: post
        url: http://tkio-receive.solar-engine.com/receive/query/attribution
        params:
          appkey: ""
          device_id: c3381276ae145b3663c8e0f6dd9f628a
          device_id_type: idfa
        validate: None
    - name: device_id为空
      request:
        method: post
        url: http://tkio-receive.solar-engine.com/receive/query/attribution
        params:
          appkey: 55705dbd45dd246751b87bba94b8c73c
          device_id: ""
          device_id_type: idfa
        validate: None
     validate可以做断言

    注意:这里面是三条测试用例,-name作为一条,字段和值之间有严格的空格限制(比如:method: post  method:和post之间有空格,要不会报错)

    2、yaml_util.py文件  -->读取yaml文件的工具类,可以放到commons类目下

    import os
    import yaml
    
    def read_testcase_yaml(yaml_path):
        # os.getcwd()获取项目根路径+yaml_path到yaml文件的路径
        with open(os.getcwd()+yaml_path,encoding="utf-8",mode="r") as f:
            # yaml加载到文件的值  -->stream是文件流,Loader是加载的方式,yaml.FullLoader所有数据
            value=yaml.load(stream=f,Loader=yaml.FullLoader)
            return value

    -->在真正传参给接口之前,测试一下yaml.util.py能不能获取到yaml文件,并且看下获取后的数据格式

    run.py类测试一下

    import pytest
    
    from publicdemo.commons.yaml_util import read_testcase_yaml
    
    if __name__ == '__main__':
        #pytest.main()
        print(read_testcase_yaml("/paraments/get_cookie.yaml"))
    /paraments/get_paraments.yaml是yaml文件所在的路径 -->因为os.getcwd()是获取项目根目录,所以直接写yaml文件所在的路径即可

    执行结果:
    {'name': '归因查询正常用例', 
      'request':
        {'method': 'post',
         'url': 'http://tkio-receive.solar-engine.com/receive/query/attribution',
         'params':
          {'appkey': '55705dbd45dd246751b87bba94b8c73c', 'device_id': 'c3381276ae145b3663c8e0f6dd9f628a', 'device_id_type': 'idfa'},
           'validate': 'None'}}

    从读取之后返回的结果可以看出,确实返回的是字段列表

    3、testcases文件夹-->test_api.py

    import time
    import pytest
    import requests
    import json
    
    from publicdemo.commons.request_util import RequestUtil
    from publicdemo.commons.yaml_util import read_testcase_yaml
    
    
    class Test_Tkio:
    
        headers = {
            "Content-Type":"application/json;charset=UTF-8"
        }
    
        # 归因查询
        @pytest.mark.run(order=1)
        @pytest.mark.smoke
        @pytest.mark.parametrize("args_name",read_testcase_yaml("/paraments/get_cookie.yaml"))
        def test_attribution(self,args_name):#注意:装饰器的名字(args_name)一定要传到用例的参数里面去
            methods = args_name["request"]["method"]
            path = args_name["request"]["url"]
            datas = args_name["request"]["params"]
            res = RequestUtil().all_sendSession(method=methods,url=path,data=json.dumps(datas),headers=Test_Tkio.headers)
            result = res.text
            print("=======test_attribution=====>"+result)
            print("--------------->",args_name)
            time.sleep(1)
    @pytest.mark.parametrize("args_name",read_testcase_yaml("/paraments/get_cookie.yaml")) 
    --> 读取yaml文件返回的字典列表复制给args_name
    methods = args_name["request"]["method"]   --》接口所需要的字段,可以直接用返回的字段args_name去截取相应的值
    yaml文件内有几条用例,这样在test_api接口执行后就会执行几条,这样就实现了自动化

    =======》一个模块下有10个接口,那么就需要10个yaml文件,一个接口一个yaml,一个yaml里面有N个用例

    二、关联接口的封装  

    把整个接口自动化里面所有的中间变量全部都保存到一个extract.yaml文件中   --> 即:接口之间关联的参数写到一个文件中,供后续使用此参数的接口使用
    ---场景:有很多接口时,只要有关联的参数,都可以取出来放到extract.yaml文件中,然后用的时候直接读取拿来用
    1、yaml_util.py  工具类中写三个方法
    #通过key读取extract.yaml
    def read_extract_yaml(key):
        with open(os.getcwd()+"/paraments/extract.yaml",encoding="utf-8",mode="r") as f:
            value = yaml.load(stream=f,Loader=yaml.FullLoader)
            return value[key]
    
    # 将数据写入extract.yaml
    def write_extract_yaml(data):
        with open(os.getcwd()+"/paraments/extract.yaml",encoding="utf-8",mode="a") as f:  #mode="a"是追加,"w"是覆盖写入
            yaml.dump(data,stream=f,allow_unicode=True) #allow_unicode=True 允许unicod编码
    # 清空extract.yaml
    def clear_extract_yaml():
        with open(os.getcwd()+"/paraments/extract.yaml",encoding="utf-8",mode="w") as f:
            f.truncate()

    2、test_tkio.py 测试类(包含两个接口:归因查询、点击查询)(点击查询传入的参数device_id,需要从归因查询接口返回的结果中获取)

    import time
    import pytest
    import requests
    import json
    
    from publicdemo.commons.yaml_util import read_testcase_yaml, write_extract_yaml, read_extract_yaml
    from pytest_pro.day02.common.request_util import RequestUtil
    
    
    class Test_Tkio:
    
        urls ="http://tkio-receive.solar-engine.com"
        headers = {
            "Content-Type":"application/json;charset=UTF-8"
        }
    
        # 归因查询
        @pytest.mark.run(order=1)
        @pytest.mark.smoke
        @pytest.mark.parametrize("args_name", read_testcase_yaml("/paraments/attribution.yaml"))
        def test_attribution(self, args_name):  # 注意:装饰器的名字(args_name)一定要传到用例的参数里面去
            methods = args_name["request"]["method"]
            path = args_name["request"]["url"]
            datas = args_name["request"]["params"]
            res = RequestUtil().all_sendSession(method=methods, url=path, data=json.dumps(datas), headers=Test_Tkio.headers)
            result = res.text
            dic_response = json.loads(result)
            # 取返回的device_id值
            device_id=dic_response['data']['install_raw_log']['device_info']['device_id']
            # 组装成一个字典,已k:v的方式存储到extract.yaml文件中
            extract_value={"device_id":device_id}
            # 调用write_extract_yaml方法写入extract.yaml
            write_extract_yaml(extract_value)
            print("=======test_attribution=====>"+device_id)
            print("--------------->", args_name)
            time.sleep(1)
    
            # 点击查询
        @pytest.mark.usermanage
        @pytest.mark.parametrize("args_name",read_testcase_yaml("/paraments/touchpoint.yaml"))
        def test_touchpoint(self,args_name):
            methods = args_name["request"]["method"]
            path = args_name["request"]["url"]
            # datas = args_name["request"]["params"]
            datas = {
                "appkey":args_name["request"]["params"]["appkey"],
                # 调用read_extract_yaml方法读取归因查询写入extract.yaml文件中的device_id
                "device_id":read_extract_yaml("device_id"),
                "device_id_type": "idfa",
                "touchpoint_type": "click",
                "attribution_type": "ua"
            }
            res = RequestUtil().all_sendSession(method=methods,url=path, data=json.dumps(datas), headers=Test_Tkio.headers)
    
            print("=====test_touchpoint=======>", res.text)
            time.sleep(1)

    这样在每次执行归因接口(test_attribution方法)的时候,extract.yaml就会写入device_id,而执行点击查询接口时(test_touchpoint方法)就会从extract.yaml中通过device_id的key取值使用

    但是会有一个问题,在多次执行接口的时候,会一直往extract.yaml里面写同样的数据,那如何解决?

    • 可以用yaml_util.py的清空方法clear_extract_yaml(),那么在什么时候使用呢?
    • 可以在写入之前清空,这里我们可以用到pytest前后置条件中的fixture,作用域为package/session:会话级别(就意味着在整个执行过程中,只会执行一次)
    • 所以在contest.py文件内可以写一个fixture调用yaml_util.py中的清空方法,并保证是会话级别-自动执行
     3、contest.py 类
    import pytest
    from publicdemo.commons.yaml_util import clear_extract_yaml
    
    # 会话级别意味着整个执行过程中只执行一次,autouse=True是自动执行
    @pytest.fixture(scope="session",autouse=True)
    def clear_yaml():
        clear_extract_yaml()

    这样我们在执行run.py(此文件内放pytest的main执行方法)时,就可以实现把extract.yaml文件中的内容先清空,然后在写入,然后在读取,即使是多次执行也会是先清空,然后在写入,然后在读取这样的操作

    自此接口自动化一个初步的框架已经成型

    三、生成美观的Allure报告

    1、官网下载allure:https://github.com/allure-framework/allure2/releases  并解压

    2、解压之后配置环境变量

    win配置:把目录:E:\allure-2.13.7\bin; 配置的path路径。

    mac配置:

    |- 终端输入:open -t ~/.bash_profile

    |- 输入下面的内容:

    export PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin
    export ALLURE="/Users/mobvista/lidong/allure-2.18.1/bin:${PATH}"
    export PATH=$PATH:$ALLURE

    |- 使配置的环境变量生效:source ~/.bash_profile

    |- 验证allure是否配置成功:allure --version     显示版本号说明安装成功

    3、生成allure报告

    3.1 生成临时报告:在根目录下创建一个temps文件夹,然后在pytest.ini文件中addopts后面输入:--alluredir=./temps --clean-alluredir

    addopts = -vs --alluredir=./temps --clean-alluredir -m "smoke or usermanage"

    temps文件下生成的是json后缀的临时报告

    3.2 生成html测试报告:

    在run.py文件中添加
    
    if __name__ == '__main__':
        pytest.main()
        # print(read_testcase_yaml("/paraments/attribution.yaml"))
        time.sleep(3)
        os.system("allure generate ./temps -o ./report --clean")

    注意:mac本如果执行报 “sh: allure: command not found”错误,具体的解决方法:https://blog.csdn.net/z1107445981/article/details/118468592

     
     
  • 相关阅读:
    Java的错误类型
    交换两个变量的值
    变量的自增、自减、自乘、自除运算
    通过Scanner从控制台获取数据
    通过args数组获取数据
    int类型与char类型的转换
    大类型向小类型转换
    小类型向大类型转换
    6 高级2 自连接 视图
    5 高级 关系 连接
  • 原文地址:https://www.cnblogs.com/frankruby/p/16428197.html
Copyright © 2020-2023  润新知