测试平台系列(34) 编写全局变量接口

简介: 编写全局变量接口

回顾


上一节咱们编写好了环境管理功能,这一章节我们来继续完善全局变量功能。

全局变量?


全局变量,其实我觉得叫它全局配置更加贴切。我理解的全局变量,其实是我们常用的一些不太变化的数据,而用例中出现的变量,我认为它是一个临时的数据,不会进行永久存储

那什么时候会用到这些变量呢?比如咱们的一些常用的测试地址,ip也好url也好,如果用例不把这块内容抽离出来,一旦地址发生变化,会出现2个问题。

  • 我们需要对用例进行修改
  • 修改的成本较大

有同学可能会说,那我去数据库里面直接update一下不就好了?是的,你可以这么做。但是谁能保证update的时候不会出错,谁又能保证每一次都能及时update了呢?所以,如果我能在全局变量页面进行统一修改,那不是事半功倍吗?这也就是我所说的,它其实更像一个全局配置

设计思路


其实我们提供的全局配置,类似于Redis,是一个key-value的形式。用户如果使用的话,只需要输入key,就能够映射到对应的value。

想象一下,如果一个value能够存放int,str, float等多种对象,那么Mysql里面这个字段该如何设计?所以这个时候我们就要加以辅佐,我们引入一个key_type字段,配合value实现一个字段多种数据类型的功能。

但我这边又不想太复杂,因为咱都是懒人。其实我们定义几种类型就够了:

  • string
  • json
  • yaml

为什么只有3种类型?因为已经够了,如果是string类型,则不需要进行json.loads()去获取数据,如果是json,我们默认通过json.loads()去转换一下数据。至于yaml,纯粹是为了新鲜

为什么说我们用json就可以拿到float,int,bool等等值呢?我们来看一个例子:

证明一下


那么我们存在数据库的值是varchar类型的0.618,那我们放入Python可以表现为这样:


a = "0.618"

那怎么得到float呢?


a = "0.618"
import json
a = json.loads(a)
print(type(a), a)

1.jpg

image.png

同理试一下bool:

2.jpg

image.png

至于string为什么和json区分开,其实json就是个string,所以我们如果遇到string类型就不做任何json.loads的处理,即可保留原滋原味

设计表


3.jpg

image.png


  • env: 变量对应的环境,如果env为0的话,说明这个变量属于全部环境。
  • enable: 变量是否可用,是一个开关字段,可临时关闭该变量

注意这里有一个联合唯一索引,根据env,key和deleted_at生成,只有当env,key,deleted_at都相等的时候,数据库才不让插入数据。这样解决了一个在environment表里面出现的问题:

当环境abc被删除以后,无法再建立名为abc的环境

4.jpg

image.png

注册model


5.jpg

image.png

编写schema

[图片上传失败...(image-423036-1624776054767)]

编写crud功能



from datetime import datetime
from sqlalchemy import desc
from app.models import Session, update_model
from app.models.gconfig import GConfig
from app.models.schema.gconfig import GConfigForm
from app.utils.logger import Log
class GConfigDao(object):
    log = Log("GConfigDao")
    @staticmethod
    def insert_gconfig(data: GConfigForm, user):
        try:
            with Session() as session:
                query = session.query(GConfig).filter_by(env=data.env, key=data.key, deleted_at=None).first()
                if query is not None:
                    return f"变量: {data.key}已存在"
                config = GConfig(**data.dict(), user=user)
                session.add(config)
                session.commit()
        except Exception as e:
            GConfigDao.log.error(f"新增变量: {data.key}失败, {e}")
            return f"新增变量: {data.key}失败, {str(e)}"
        return None
    @staticmethod
    def update_gconfig(data: GConfigForm, user):
        try:
            with Session() as session:
                query = session.query(GConfig).filter_by(id=data.id, deleted_at=None).first()
                if query is None:
                    return f"变量{data.key}不存在"
                update_model(query, data, user)
                session.commit()
        except Exception as e:
            GConfigDao.log.error(f"编辑变量失败: {str(e)}")
            return f"编辑变量失败: {str(e)}"
        return None
    @staticmethod
    def list_gconfig(page, size, env=None, key=None):
        try:
            search = [GConfig.deleted_at == None]
            with Session() as session:
                if env:
                    search.append(GConfig.env == env)
                if key:
                    search.append(GConfig.name.ilike("%{}%".format(key)))
                data = session.query(GConfig).filter(*search)
                total = data.count()
                return data.order_by(desc(GConfig.created_at)).offset((page - 1) * size).limit(
                    size).all(), total, None
        except Exception as e:
            GConfigDao.log.error(f"获取变量列表失败, {str(e)}")
            return [], 0, f"获取变量列表失败, {str(e)}"
    @staticmethod
    def delete_gconfig(id, user):
        try:
            with Session() as session:
                query = session.query(GConfig).filter_by(id=id).first()
                if query is None:
                    return f"变量{id}不存在"
                query.deleted_at = datetime.now()
                query.update_user = user
                session.commit()
        except Exception as e:
            GConfigDao.log.error(f"删除变量失败: {str(e)}")
            return f"删除变量失败: {str(e)}"
        return None

看过上一篇文章的都知道细节,其实我写代码的时候也是copy的。

大家有没有发现: 编写一个crud的功能是真的不难!基本可以按照固定的套路来,像我都是copy的上一个功能点的代码,然后稍作改动。

编写核心接口



from fastapi import Depends
from app.dao.config.GConfigDao import GConfigDao
from app.handler.fatcory import ResponseFactory
from app.models.schema.gconfig import GConfigForm
from app.routers import Permission
from app.routers.config.environment import router
from config import Config
@router.get("/gconfig/list")
async def list_gconfig(page: int = 1, size: int = 8, env: int = None, key: str = "", user_info=Depends(Permission())):
    data, total, err = GConfigDao.list_gconfig(page, size, env, key)
    if err:
        return dict(code=110, msg=err)
    return dict(code=0, data=ResponseFactory.model_to_list(data), total=total, msg="操作成功")
@router.post("/gconfig/insert")
async def insert_gconfig(data: GConfigForm, user_info=Depends(Permission(Config.ADMIN))):
    err = GConfigDao.insert_gconfig(data, user_info['id'])
    if err:
        return dict(code=110, msg=err)
    return dict(code=0, msg="操作成功")
@router.post("/gconfig/update")
async def update_gconfig(data: GConfigForm, user_info=Depends(Permission(Config.ADMIN))):
    err = GConfigDao.update_gconfig(data, user_info['id'])
    if err:
        return dict(code=110, msg=err)
    return dict(code=0, msg="操作成功")
@router.get("/gconfig/delete")
async def delete_gconfig(id: int, user_info=Depends(Permission(Config.ADMIN))):
    err = GConfigDao.delete_gconfig(id, user_info['id'])
    if err:
        return dict(code=110, msg=err)
    return dict(code=0, msg="操作成功")

其实大体上还是和之前的router差不多,但是这里多了一个细节:

  • 当config router下面有个文件的时候会怎么样?

6.jpg

image.png

我们这里有一个gconfig和一个envrionment,里面大概8个接口。

envrionment定义了ApiRouter的router对象,gconfig引入了router对象。那么我们的接口会被成功注册吗?

答案是不会的,大家可以试一试。

因为顺序是这样的:

  1. router = ApiRouter() # environment中发生
  2. pity.include_router(config.router)
  3. router注册gconfig的接口

因为咱们运行的是main.py文件,main.py在import router的时候肯定是最先发生的。其实flask也会遇到这样的问题,解决方法有2个。

  • 快速法
    main.py注册router的时候,选用最后一个。
    举个例子,envrionment创建了router,gconfig引入了router,我们从gconfig import router就行。但这样不会太保险,因为还是可能会遗漏或者搞错。
  • 利用init.py
    7.jpg


image.png


最后在注册的时候import init.py里面的router即可。简单的说就是搞一个专门收集router的文件,最后集中注册。

8.jpg

image.png

总结

本期除了写了全局变量功能以外,还解决了2个问题:

  • 联合索引问题
  • router注册问题


希望对大家有帮助~




相关文章
|
1月前
|
数据可视化 前端开发 测试技术
接口测试新选择:Postman替代方案全解析
在软件开发中,接口测试工具至关重要。Postman长期占据主导地位,但随着国产工具的崛起,越来越多开发者转向更适合中国市场的替代方案——Apifox。它不仅支持中英文切换、完全免费不限人数,还具备强大的可视化操作、自动生成文档和API调试功能,极大简化了开发流程。
|
5天前
|
JSON 前端开发 测试技术
大前端之前端开发接口测试工具postman的使用方法-简单get接口请求测试的使用方法-简单教学一看就会-以实际例子来说明-优雅草卓伊凡
大前端之前端开发接口测试工具postman的使用方法-简单get接口请求测试的使用方法-简单教学一看就会-以实际例子来说明-优雅草卓伊凡
44 10
大前端之前端开发接口测试工具postman的使用方法-简单get接口请求测试的使用方法-简单教学一看就会-以实际例子来说明-优雅草卓伊凡
|
3天前
|
JSON 前端开发 API
以项目登录接口为例-大前端之开发postman请求接口带token的请求测试-前端开发必学之一-如果要学会联调接口而不是纯写静态前端页面-这个是必学-本文以优雅草蜻蜓Q系统API为实践来演示我们如何带token请求接口-优雅草卓伊凡
以项目登录接口为例-大前端之开发postman请求接口带token的请求测试-前端开发必学之一-如果要学会联调接口而不是纯写静态前端页面-这个是必学-本文以优雅草蜻蜓Q系统API为实践来演示我们如何带token请求接口-优雅草卓伊凡
25 5
以项目登录接口为例-大前端之开发postman请求接口带token的请求测试-前端开发必学之一-如果要学会联调接口而不是纯写静态前端页面-这个是必学-本文以优雅草蜻蜓Q系统API为实践来演示我们如何带token请求接口-优雅草卓伊凡
|
1月前
|
存储 测试技术 数据库
接口测试工具攻略:轻松掌握测试技巧
在互联网快速发展的今天,软件系统的复杂性不断增加,接口测试工具成为确保系统稳定性的关键。它如同“翻译官”,模拟请求、解析响应、验证结果、测试性能并支持自动化测试,确保不同系统间信息传递的准确性和完整性。通过Apifox等工具,设计和执行测试用例更加便捷高效。接口测试是保障系统稳定运行的第一道防线。
|
1月前
|
Web App开发 JSON 测试技术
API测试工具集合:让接口测试更简单高效
在当今软件开发领域,接口测试工具如Postman、Apifox、Swagger等成为确保API正确性、性能和可靠性的关键。Postman全球闻名但高级功能需付费,Apifox则集成了API文档、调试、Mock与自动化测试,简化工作流并提高团队协作效率,特别适合国内用户。Swagger自动生成文档,YApi开源但功能逐渐落后,Insomnia界面简洁却缺乏团队协作支持,Paw仅限Mac系统。综合来看,Apifox是国内用户的理想选择,提供中文界面和免费高效的功能。
|
1月前
|
消息中间件 监控 小程序
电竞陪玩系统架构优化设计,陪玩app如何提升系统稳定性,陪玩小程序平台的测试与监控
电竞陪玩系统架构涵盖前端(React/Vue)、后端(Spring Boot/php)、数据库(MySQL/MongoDB)、实时通信(WebSocket)及其他组件(Redis、RabbitMQ、Nginx)。通过模块化设计、微服务架构和云计算技术优化,提升系统性能与可靠性。同时,加强全面测试、实时监控及故障管理,确保系统稳定运行。
|
2月前
|
监控 JavaScript 测试技术
postman接口测试工具详解
Postman是一个功能强大且易于使用的API测试工具。通过详细的介绍和实际示例,本文展示了Postman在API测试中的各种应用。无论是简单的请求发送,还是复杂的自动化测试和持续集成,Postman都提供了丰富的功能来满足用户的需求。希望本文能帮助您更好地理解和使用Postman,提高API测试的效率和质量。
135 11
|
3月前
|
人工智能 供应链 安全
AI辅助安全测试案例某电商-供应链平台平台安全漏洞
【11月更文挑战第13天】该案例介绍了一家电商供应链平台如何利用AI技术进行全面的安全测试,包括网络、应用和数据安全层面,发现了多个潜在漏洞,并采取了有效的修复措施,提升了平台的整体安全性。
137 4
|
3月前
|
JSON Java 测试技术
SpringCloud2023实战之接口服务测试工具SpringBootTest
SpringBootTest同时集成了JUnit Jupiter、AssertJ、Hamcrest测试辅助库,使得更容易编写但愿测试代码。
92 3
|
3月前
|
监控 安全 测试技术
构建高效的精准测试平台:设计与实现指南
在软件开发过程中,精准测试是确保产品质量和性能的关键环节。一个精准的测试平台能够自动化测试流程,提高测试效率,缩短测试周期,并提供准确的测试结果。本文将分享如何设计和实现一个精准测试平台,从需求分析到技术选型,再到具体的实现步骤。
214 1