• Pytest接口测试框架实战项目搭建(二)


    一、前言

      业务系统的登录均要经过统一登录系统S,本篇演示统一登录处理,一个是内部业务系统C(其余内部业务系统AB用的都是相同账号密码),一个是外部用户使用的系统W,因为账号密码以及headers信息都不一样,所以要分开处理登录。这里要先贴一下请求要用到的数据。

      说明:登录进了S系统,拿到token即可直接请求内部业务系统ABC的接口,同理外部业务系统W亦是如此。所以本篇主要讲述的是如何登录S系统

    1、conf/config.ini

      接口请求时需要拿到配置文件中的域名地址,env可切换环境,即不用改业务代码,直接改配置文件即可适配不同测试环境的接口自动化测试。

         y_api_url,是业务系统ABCW的接口域名,s_api_url是登录系统S的接口域名。

    [ENV]
    env = QA1
    
    [QA1]
    y_api_url = https://qa1-api.y.cn
    s_api_url = https://qa-s-xxx.cn
    
    [QA2]
    y_api_url = https://qa1-api.y.cn
    s_api_url = https://qa-s-xxx.cn

    2、data/userInfo.yaml

      要拿到登录token,需要先登录S系统,S登录接口是嵌入到各个业务系统,所以请求体是一样的只是账号密码不一样,故要分开来,内部业务系统ABC均可用s_login_info的用户信息,外部业务系统W用的是w_login_info的用户信息。

    QA1:
      s_login_info:
        loginFromServer: 'https://qa-xxx.cn/#/'
        loginFromSystemCode: S
        #passwordVersion: 1 #去掉该参数,password传输可不加密
        username: zhangsan
        password: 1231234
        verification:
    
      w_login_info:
        loginFromServer: 'https://qa-xxx.cn/#/'
        loginFromSystemCode: S
        #passwordVersion: 1 #去掉该参数,password传输可不加密
        username: lisi
        password: 123456
        verification:
    
    QA2:
      s_login_info:
        loginFromServer: 'https://qa-xxx.cn/#/'
        loginFromSystemCode: S
        #passwordVersion: 1 #去掉该参数,password传输可不加密
        username: zhangsan111
        password: 1231234
        verification:
    
      w_login_info:
        loginFromServer: 'https://qa-xxx.cn/#/'
        loginFromSystemCode: S
        #passwordVersion: 1 #去掉该参数,password传输可不加密
        username: lisi222
        password: 123456
        verification:

    3、data/headers.json

      内部业务系统ABC均可用s_login_info的用户信息,外部业务系统W用的是w_login_info的用户信息,其实请求体是一样的只是账号密码不一样,所以要分开来。

    {
      "QA1": {
        "s_login_headers": {
          "Content-Type": "application/x-www-form-urlencoded",
          "Accept": "application/json, text/plain, */*"
        },
        "s_headers": {
          "Content-Type": "application/json;charset=UTF-8",
          "Accept": "application/json, text/plain, */*",
          "sToken": ""
        },
        "c_headers": {
          "T-Id": "7",
          "System-Code": "C",
          "Content-Type": "application/json;charset=UTF-8",
          "Accept": "application/json, text/plain, */*",
          "sToken": ""
        },
        "w_headers": {
          "T-Id": "12095",
          "System-Code": "W",
          "Content-Type": "application/json;charset=UTF-8",
          "Accept": "application/json, text/plain, */*",
          "sToken": ""
        }
      },
      "QA2": {
        "s_login_headers": {
          "Content-Type": "application/x-www-form-urlencoded",
          "Accept": "application/json, text/plain, */*"
        },
        "c_headers": {
          "T-Id": "7",
          "System-Code": "C",
          "Content-Type": "application/json;charset=UTF-8",
          "Accept": "application/json, text/plain, */*",
          "sToken": ""
        }
      }
    }

    4、conf/api_path.py

      该文件存储的是项目中用到的所有接口路径,目前只展示统一登录需要用到的api。

    # -*- coding:utf-8 -*-
    '''
    @Date:2022/10/3  20:56
    @Author:一加一
    '''
    
    from tools.operate_config import OperateConfig
    from urllib.parse import urljoin
    
    class ApiPath:
    
        '''管理api地址'''
    
        def __init__(self,env=None):
            if env is None:
                self.env = OperateConfig().get_node_value('ENV', 'env')
            else:
                self.env = env
         self.y_api_url = OperateConfig().get_node_value(self.env,'y_api_url') # 读取配置文件config.ini的业务系统接口域名
            self.s_api_url = OperateConfig().get_node_value(self.env, 's_api_url') #读取配置文件config.ini 的s系统接口域名
    
            # s系统 api
            self.s_login_url = urljoin(self.s_api_url, "/saas-xxx/login") #登录
            self.s_exchangeToken_url = urljoin(self.s_api_url, "/saas-xxx/exchangeToken") #生成sToken
            self.employee_paging_list = urljoin(self.s_api_url,"/saas-xxx/list") #查询员工列表获取companyId

    二、封装方法:获取JSON

      要登录的话肯定要涉及接口请求了,所以这里首先封装下读取json文件的方法,具体如下。

    1、tools/get_userjson.py

      tools文件夹下新建get_userjson.py文件,源码如下:

    • get_yaml主要用于读取data/userInfo.yaml里的用户信息
    • OperateConfig主要读取config.ini里的域名地址

    from tools.operate_config import get_yaml,OperateConfig
    
    class GetuserJson:
    
        def __init__(self, env=None):
            if env is None:
                env = OperateConfig().get_node_value('ENV', 'env')
            self.env = env
            self.user_info = get_yaml(self.env)
    
        # 统一登录系统s 登陆的用户信息
        def  get_s_login_info(self):
            s_login_info = self.user_info['s_login_info']
            return s_login_info
    
        # 业务系统W 登陆的用户信息
        def  get_w_login_info(self):
            w_login_info = self.user_info['w_login_info']
            return w_login_info

    2、tools/get_headerjson.py

      tools文件夹下新建get_headerjson.py文件,源码如下:

    • 用于登录S系统用到的:get_s_login_headers,获取headers.json里名为"s_login_headers”的json串
    • 用于S系统查询公司id用到的:get_s_headers,获取headers.json里名为"s_headers”的json串
    • 用于登录成功将获取到的token值set进去:set_s_headers,往json文件里set字段值
    # -*- coding:utf-8 -*-
    from conf.setting import CASE_DATA_PATH
    from tools.operate_json import OperationJson
    import os
    from tools.operate_config import get_yaml,OperateConfig
    
    class GetHeaderjson:
    
        def __init__(self,env=None):
            if env is not None:
                self.env = env
            else:
                self.env = OperateConfig().get_node_value('ENV', 'env')
            self.headers_json = os.path.join(CASE_DATA_PATH, "headers.json")
    
        def get_s_login_headers(self):
            return OperationJson(self.headers_json).key_get_data(self.env,"s_login_headers")
        def get_s_headers(self):
            return OperationJson(self.headers_json).key_get_data(self.env,"s_headers")
        def set_s_headers(self,s_token):
            OperationJson(self.headers_json).write_datas(s_token,self.env, "s_headers", "sToken")
    def get_c_headers(self):
            return OperationJson(self.headers_json).key_get_data(self.env,"c_headers")
        def set_c_headers(self,s_token):
            OperationJson(self.headers_json).write_datas(s_token,self.env, "c_headers", "sToken")
    
        def get_w_headers(self):
            return OperationJson(self.headers_json).key_get_data(self.env, "w_headers")
        def set_w_headers(self,s_token):
            OperationJson(self.headers_json).write_datas(s_token,self.env, "w_headers", "sToken")
        def set_w_headers_companyId(self,companyId):
            OperationJson(self.headers_json).write_datas(companyId,self.env, "w_headers", "T-Id")

    三、统一登录处理conftest.py

    1、conftest.py源码如下

      conftest文件之前的博客有讲过,常用来处理用例的前置条件,文件名称是pytest框架写死的,即是在执行用例前框架会先执行一次conftest.py的代码。

      框架思想:

      1)内部业务系统 储如ABC,接口请求时header的token需要实时获取,所以需要在接口请求前先完成登录,并且将登录后成功的token值set到headers.json里相应json串对应的token字段,如此token便不会过期,永远都是最新的,可看test_s_login函数处理。

      2)外部业务系统W,同理token需要取最新,以及接口请求头的T-Id也是,所以需要在接口请求前先完成登录,并且登录成功后将最新的tooken,T-id值set到headers.json里相应json串对应的token字段,可看test_w_login函数处理。

    '''
    @Date:2022/10/2  14:22
    @Author:一加一
    '''
    
    import pytest
    from tools.common import *
    from tools.get_headerjson import GetHeaderjson
    from conf.api_path import ApiPath
    from tools.get_userjson import GetuserJson
    from tools.get_wjson import *
    '''处理登录:统一登录S、业务系统登录W'''
    
    # 实例化对象
    api_path = ApiPath()
    get_header = GetHeaderjson(None)
    get_userinfo = GetuserJson(None)
    get_wjson = GetwJson(None)
    
    
    @pytest.fixture(scope="session",autouse=True)
    def test_s_login():
        # s登录:用户名密码登录
        url = api_path.s_login_url #调用api_path方法获取url
        headers = get_header.get_s_login_headers() #调用get_header获取s系统接口请求头
        data = get_userinfo.get_s_login_info() #调用get_userinfo获取入参
        res_json = Common.r_post_form(url=url, headers=headers, data=data)
        # 获取code
        code = res_json['data'].split('?')[-1]
    
        # 生成stoken
        res_json = Common.r_post_form(url=api_path.s_exchangeToken_url,headers=get_header.get_s_login_headers(),data=code)
        # 将生成的sToken写入headers.json文件
        get_header.set_c_headers(res_json['data']['sToken'])
        get_header.set_p_headers(res_json['data']['sToken'])
    
    @pytest.fixture(scope="session",autouse=True)
    def test_w_login():
        # s登录:用户名密码登录
        url = api_path.s_login_url #调用api_path方法获取url
        headers = get_header.get_s_login_headers() #调用get_header获取s请求头
        data = get_userinfo.get_w_login_info() #调用get_userinfo获取入参
        res_json = Common.r_post_form(url=url, headers=headers, data=data)
        # 获取code
        code = res_json['data'].split('?')[-1]
    
        # 生成stoken
        res_json = Common.r_post_form(url=api_path.s_exchangeToken_url,headers=get_header.get_s_login_headers(),data=code)
        # 将生成的sToken写入headers.json文件
        get_header.set_w_headers(res_json['data']['sToken'])
        get_header.set_s_headers(res_json['data']['sToken'])
    
        # 查询s系统员工列表获取T-id写入headers.json文件的T-Id
        res_json = Common.r_s_post(url=api_path.employee_paging_list,
                                 headers=get_header.get_s_headers(),
                                 json=get_wjson.get_w_companyId())
        # 将响应结果转换成json格式
        rep_json = res_json.json()
        # 断言
        Common.assert_s_code_message(rep_json)
        # 将生成的companyId写入headers.json文件(w_headers对应的T-Id)
        TenantId = str(rep_json['data']['pageData'][0]['companyId'])
        get_header.set_w_headers_companyId(TenantId)

    四、新建测试用例 testcase/test_case.py

      主要用于调试执行用例前是否会先处理conftest.py代码,以及调试conftest.py的登录代码

    '''
    @Date:2022/11/12  13:35
    @Author:一加一
    '''
    
    import allure
    
    @allure.feature("测试业务")
    @allure.story("测试订单")
    class TestCase:
        @allure.title("case1:获取列表")
        def test_case1(self):
            with allure.step("step1:获取列表"):
                print("测试第一步")
            with allure.step("step2:获取响应结果"):
                print("测试第二步")

     五、执行test_case.py文件后,生成的日志如下

      由日志可知用例执行前会正确先执行conftest.py的代码

      

    重点:学习资料  

    600g的学习资料懂的都懂

  • 相关阅读:
    Transformer12
    es6 语法,在个别浏览器中不兼容的处理办法
    有哪些挣钱软件一天能赚几十元?盘点十个能长期做下去的挣钱软件
    孙荣辛|大数据穿针引线进阶必看——Google经典大数据知识
    C++中类模板的语法与使用
    MAUI与Blazor共享一套UI,媲美Flutter,实现Windows、macOS、Android、iOS、Web通用UI
    Python汽车销售系统的设计与实现毕业设计-附源码191807
    Windows下安装配置Nginx
    STM32CubeMX安装、使用、配置
    限制LitstBox控件显示指定行数的最新数据(1/3)
  • 原文地址:https://blog.csdn.net/m0_60054525/article/details/128106052