高效自动化测试框架-优秀实践02-接口

这篇具有很好参考价值的文章主要介绍了高效自动化测试框架-优秀实践02-接口。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

高效自动化测试框架-优秀实践02-接口

高效实践点

  1. 编写接口的操作的时候只需要编写接口的url,请求方法,请求体的样例

  2. 其他的将接口封装成服务或者关键字的操作,全部使用装饰器来封装,能做到高效的解耦

  3. 在表示层编写业务测试用例的时候,可以使用函数式的编程方式,非常易读,还非常易于copy,提升编写效率

问题背景

  1. 业务测试用例编写完成之后,需要很多时间去调试,常常是针对入参和返回值做处理

  2. 业务测试用例很不整齐,即代码没有对齐,也不能直观看出脚本的行为,需要仔细读取函数的名称,并进一步理解

  3. 业务脚本的函数命名不规范,不统一,导致不易于理解和修改

  4. 关键字中常常由很多重复的代码,比如接收入参并填充进入请求体中,对于返回值有常常需要根据json格式去取出响应数据

  5. 最开始的框架,提供了很多功能,很灵活,但是多就是少,功能越多越灵活就会导致学习成本和维护成本直线上升,还不如直接统一格式

  6. 关键字中的逻辑是多种多样的,如果需要维护,有可能需要对很多个关键字去维护,耗费时间巨大

解决思路

  1. Api接口的封装,分成4个操作方式去封装,即增删查改

  2. 每个操作行为封装一个接口函数,并且接口中只包含URL,请求体,请求方法

  3. 对于接口的行为,全部由统一的装饰器去封装,分别针对请求体为json,urlencode,xml,html等格式去封装,默认是json

  4. 对于接口行为的封装,将入参装载进入请求体的方法统一封装,即自动寻找对应的数据,然后填充到请求体中去

  5. 对于接口行为的封装,需要提取返回值的时候,上层传入目标值名称,和对应的正则表达式(jsonpath),然后获得对应的数据

相关代码

接口代码示例

from core.logic import Api
​
​
@Api.json
def add_goods(goodsSn="", name="", **kwargs):
    req_method = "POST"
    url = "admin/goods/create"
    body_data = {
        "goods": {
            "picUrl": "",
            "gallery": [],
            "isHot": False,
            "isNew": True,
            "isOnSale": True,
            "goodsSn": "9001",
            "name": None
        },
        "specifications": [{
            "specification": "规格",
            "value": "标准",
            "picUrl": ""
        }],
        "products": [{
            "id": 0,
            "specifications": ["标准"],
            "price": "66",
            "number": "66",
            "url": ""
        }],
        "attributes": []
    }
    return req_method, url, body_data
​
​
@Api.json
def rmv_goods(id="", **kwargs):
    req_method = "POST"
    url = "admin/goods/delete"
    body_data = {"id": None}
    return req_method, url, body_data
​
​
def lst_goods(name="", **kwargs):
    req_method = "GET"
    url = "admin/goods/list"
    body_data = {
        "name": "",
        "order": "desc",
        "sort": "add_time"
    }
    return req_method, url, body_data
​
def dtl_goods(id="", **kwargs):
    req_method = "GET"
    url = "admin/goods/detail"
    body_data = {"id": None}
    return req_method, url, body_data
​

用于封装接口函数,并提供入参填充,返回值提取,和日志打印功能的的装饰器

E:\Develop\LoranTest\core\logic.py

import jsonpath
import functools
import json
from core.base_api import BaseApi
from core.logger.logger_interface import logger
​
​
class RequestData:
    class KeyError(Exception):
        def __init__(self, error_key):
            error_dict = {
                "find_too_many_key": "The key value is incorrect. The request data contains at least two keys named $key. "
                                     "Please modify the incoming key name, that is, $parent key + $key",
                "can_not_find_key": "The key you entered could not be found in the dictionary",
            }
            self.error_info = error_dict[error_key]
​
        def __str__(self):
            return repr(self.error_info)
​
    class FindKeyError(Exception):
        def __str__(self):
            return repr("The key you entered could not be found in the dictionary")
​
    def __init__(self):
        self.data = None
        self.out_data = None
​
    def set_data(self, json_dict):
        self.data = json_dict
        self.out_data = self.data
​
    def iter_node(self, rows, road_step, target):
        if isinstance(rows, dict):
            key_value_iter = (x for x in rows.items())
        elif isinstance(rows, list):
            key_value_iter = (x for x in enumerate(rows))
        else:
            return
        for key, value in key_value_iter:
            current_path = road_step.copy()
            current_path.append(key)
            if key == target:
                yield current_path
            if isinstance(value, (dict, list)):
                yield from self.iter_node(value, current_path, target)
​
    def find_one(self, key: str) -> list:
        path_iter = self.iter_node(self.data, [], key)
        for path in path_iter:
            return path
        return []
​
    def find_all(self, key: str) -> list:
        path_iter = self.iter_node(self.data, [], key)
        return list(path_iter)
​
    def _edit_one_path(self, paths: list, value):
        alias_of_data = self.out_data
        for path in paths[0:-1]:
            alias_of_data = alias_of_data[path]
        alias_of_data[paths[-1]] = value
​
    def change(self, key: str, value):
        if "_" not in key:
            res = self.find_all(key)
            if len(res) > 1:
                raise self.KeyError("find_too_many_key")
            paths = res[0]
            self._edit_one_path(paths, value)
        else:
            key_list = key.split("_")
            res = self.find_all(key_list[-1])
            for temp in key_list:
                if temp not in res[0]:
                    raise self.KeyError("can_not_find_key")
            paths = res[0]
            self._edit_one_path(paths, value)
            pass
​
        return self.out_data
​
    def modify(self, json_dict, **kwargs):
        out_data = json_dict
        for key, value in kwargs.items():
            self.set_data(out_data)
            out_data = self.change(key, value)
        return out_data
​
​
class ResponeseData:
​
    def fetch_one_value(self, data, var_info):
        var_name = var_info[0]
        json_path_reg = var_info[1]
        value = jsonpath.jsonpath(data, json_path_reg)[0]
        return value
​
    def fetch_all_value(self, data, fetch_info):
        # TODO 这里有可能存在一个问题,只对单个调教的信息提取做处理,未对多条件的进行处理
        for info in fetch_info:
            return self.fetch_one_value(data, info)
​
​
class Api:
    @classmethod
    def json(self, func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            """我是 wrapper 的注释"""
            # 提取fetch入参
            fetch = None
            if "fetch" in kwargs.keys():
                fetch = kwargs["fetch"]
                del kwargs['fetch']
​
            res = func(*args, **kwargs)
            logger.debug(func.__name__ + "::kwargs: " + json.dumps(kwargs))
​
            req_method, url, body_data = res
            req_body = RequestData().modify(body_data, **kwargs)
            logger.debug(func.__name__ + "::req_body: " + json.dumps(req_body))
​
            req_api = BaseApi(role="admin")
            rsp_data = req_api.send(method=req_method, url=url, json=req_body)
            logger.debug(func.__name__ + "::req_body: " + json.dumps(rsp_data))
​
            # 针对fetch入参做处理
            if fetch:
                fetch_var = ResponeseData().fetch_all_value(rsp_data, fetch)
                logger.debug(func.__name__ + "::req_body: " + json.dumps(fetch_var))
        return wrapper
​
    def form(self):
        pass
​
    def urlencoded(self):
        pass
​
    def binary(self):
        pass
​
    def test(self):
        pass
​
    def js(self):
        pass
​
    def html(self):
        pass
​
    def xml(self):
        pass
​
​
​

接口的请求的基类

E:\Develop\LoranTest\core\base_api.py

import json
import requests
from core.logger.logger_interface import logger
from config.environment import Environment
​
​
class BaseApi:
    def __init__(self, role=None):
        env = Environment()
        self.base_url = env.base_url
        self.token = None
        self.role = role
​
    def _get_token(self, role=None):
        if role != "admin" and role != "client":
            raise ValueError
        url = {
            "admin": "admin/auth/login",
            "client": "wx/auth/login",
        }
        data = {
            "admin": {"username": "admin123", "password": "admin123"},
            "client": {"username": "user123", "password": "user123"},
        }
        req_token = {
            "admin": "X-Litemall-Admin-Token",
            "client": "X-Litemall-Token",
        }
        req = requests.request("post", self.base_url + url[role], json=data[role])
        self.token = {req_token[role]: req.json()["data"]["token"]}
        pass
​
    def _set_token(self, request_infos):
        if self.token is None:
            self._get_token(role=self.role)
​
        if request_infos.get("headers"):
            request_infos["headers"].update(self.token)
        else:
            request_infos["headers"] = self.token
        return request_infos
​
    def send(self, method="", url="", **kwargs):
        kwargs = self._set_token(kwargs)
        rsp = requests.request(method, self.base_url + url, **kwargs)
        rsp_json = rsp.json()
        logger.debug(f"BaseApi::send ==> {url}接口的响应为{json.dumps(rsp_json, indent=2, ensure_ascii=False)}")
        return rsp_json
​
​

待改进的地方

  1. 返回值目前仅支持返回一条数据

  2. 请求的积累中,需要重复去获取token信息,速度慢,以后可以改成直接读取redis的方式去实现

  3. 查询某类资源的时候,需要用变量去接收返回值,代码格式还不够统一,可以考虑使用传入类变量的方式去实现,直接接收返回值的方式,并且Python在作用于这块限制的比较严格

项目地址

GitHub - WaterLoran/LoranTest文章来源地址https://www.toymoban.com/news/detail-405154.html

到了这里,关于高效自动化测试框架-优秀实践02-接口的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Apifox-比postman更优秀的接口自动化测试平台

    Apifox  是 API 文档、API 调试、API Mock、API 自动化测试一体化协作平台,定位  Postman + Swagger + Mock + JMeter 。通过一套系统、一份数据,解决多个系统之间的数据同步问题。只要定义好 API 文档,API 调试、API 数据 Mock、API 自动化测试就可以直接使用,无需再次定义;API 文档和

    2024年02月03日
    浏览(39)
  • Apifox(1)比postman更优秀的接口自动化测试平台

    Apifox  是 API 文档、API 调试、API Mock、API 自动化测试一体化协作平台,定位  Postman + Swagger + Mock + JMeter 。通过一套系统、一份数据,解决多个系统之间的数据同步问题。只要定义好 API 文档,API 调试、API 数据 Mock、API 自动化测试就可以直接使用,无需再次定义;API 文档和

    2024年02月09日
    浏览(36)
  • pythonUI自动化-02-unittest框架

    cookie操作 1. 基础层: base 用来封装selenium原生方法 baseutil.py:  初始化 basepage.py 2. 页面对象层: 页面的元素和操作(一个页面一个文件) login_page.py 3. 测试用例层: testcase 准备测试用例和数据 4. 数据驱动层: 读取测试数据excel  5. 网上下载: HTMLTestRunner.py 用于生成html报告 6. 创建测试

    2024年02月15日
    浏览(30)
  • Python编程:高效数据处理与自动化任务实践

    一、引言 Python,作为一种解释型、交互式、面向对象的编程语言,凭借其简洁易懂的语法和强大的功能库,已经成为数据科学、机器学习、Web开发等多个领域的首选工具。本文将探讨Python在数据处理和自动化任务方面的应用,通过具体的代码案例展示Python的强大功能。 二、

    2024年04月26日
    浏览(23)
  • 自动化测试:让软件测试更高效更愉快!

    谈谈那些实习测试工程师应该掌握的基础知识(一)_什么时候才能变强的博客-CSDN博客 https://blog.csdn.net/qq_17496235/article/details/131839453 谈谈那些实习测试工程师应该掌握的基础知识(二)_什么时候才能变强的博客-CSDN博客 https://blog.csdn.net/qq_17496235/article/details/131850980 自动化测

    2024年02月14日
    浏览(43)
  • 如何实现高效的Web自动化测试?

    随着互联网的快速发展,Web应用程序的重要性也日益凸显。为了保证Web应用程序的质量和稳定性, Web自动化测试 成为必不可少的一环。然而,如何实现高效的Web自动化测试却是一个值得探讨的课题。 首先,选择合适的测试工具是关键。市面上有许多成熟的Web自动化测试工具

    2024年02月07日
    浏览(30)
  • 接口自动化测试实践指导(下):接口自动化测试断言设置思路

    作者 : 石臻臻 , CSDN博客之星Top5 、 Kafka Contributor 、 nacos Contributor 、 华为云 MVP , 腾讯云TVP , 滴滴Kafka技术专家 、 KnowStreaming 。 KnowStreaming 是滴滴开源的Kafka运维管控平台, 有兴趣一起参与参与开发的同学,但是怕自己能力不够的同学,可以联系我,当你导师带你参与开源! 。 在

    2024年01月18日
    浏览(60)
  • 收银台项目——Web自动化测试(简单高效)

     使用Java语言Spring框架实现的收银台项目。用户完成注册登录后进入首页,可以进行购买商品和浏览商品订单的功能,收银员可以对商品进行上架,更新商品。双方都能够浏览到商品信息。 一,测试介绍 使用Java语言实现 Web自动化测试 ,对各页面的元素进行查找确认是否存

    2024年02月13日
    浏览(30)
  • 【自动化测试】几种常见的自动化测试框架

    在软件测试领域,自动化测试框架有很多,这里主要介绍几种常用的自动化测试框架。 pytest 是 Python 的一种单元测试框架,与 Python 自带的 unittest 测试框架类似,但是比 unittest 框架使用起来更简洁,效率更高。主要有以下几个特点: 简单灵活,容易上手。 支持参数化。 能

    2024年02月07日
    浏览(33)
  • 自动化测试(三):接口自动化pytest测试框架

    API:Application Programming Interface 接口自动化按照自动化的工具可分为 基于 接口测试工具 的接口自动化 eg1:Postman+Newman+git/Svn+Jenkins(基于Javascript语言)接口自动化 Postman :创建和发送 API 请求,并对响应进行断言和验证。 Newman : Postman 的命令行工具,它允许测试人员在没有界

    2024年02月10日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包