最强自动化框架,Pytest自动化测试-动态切换环境实战(超细整理)

目录:导读

    • 前言
    • 一、Python编程入门到精通
    • 二、接口自动化项目实战
    • 三、Web自动化项目实战
    • 四、App自动化项目实战
    • 五、一线大厂简历
    • 六、测试开发DevOps体系
    • 七、常用自动化测试工具
    • 八、JMeter性能测试
    • 九、总结(尾部小惊喜)


前言

在开始前,我们可以先思考几个问题:动态切换测试环境的目的是什么(能够解决什么问题)?该如何实现(实现方案)?具体步骤是什么(实现过程)?

1、动态切换测试环境的目的是什么?

动态切换测试环境的目的是什么,或者说它能解决什么样的问题:
便于快速验证功能在不同环境中的表现。

比如:有的功能(背后的接口)在开发环境是正常的,但到了测试或预发布环境就出问题了,可以便于快速验证各个功能在不同环境中的表现;

省去修改配置参数的繁琐步骤。通常情况下,我们的配置信息都是写在配置文件中,然后测试用例读取配置文件中不同的配置信息。如果想要切换环境,就需要修改配置文件或读取配置的逻辑。

而动态切换测试环境则可以自动根据我们传入的命令行参数和预制好的读取配置的策略,自动识别、解析并返回对应的数据。

为测试框架赋能。测试框架要能做到,一套脚本多环境运行,支持环境切换,并且能根据环境进行自动化的配置(包括系统配置、测试数据配置等)。

其实以上总结起来就是:一套测试脚本,能根据环境进行自动化的配置,省去手动配置参数的步骤,可以实现在多环境中运行,从而快速验证各个接口及相关服务在不同环境中的表现。

2、动态切换测试环境如何实现?

实现方案:
我们希望:可以有个开关,自由控制执行脚本的运行环境,而不是需要我们手动修改。

比如:选择dev时,自动读取的是开发环境的配置及测试数据:url、数据库配置、账号密码、测试数据;
当切换到test时,自动读取的是测试环境的配置及测试数据。

大致实现原理如下所示:

C1

用户通过pytest命令行传入参数驱动脚本执行(pytest_addoption用于实现自定义命令行参数);

fixture函数get_env用于获取用户输入的命令行参数,传递给fixture.py中的各个fixture函数;

fixture.py中的各个fixture函数根据get_env提供的环境参数值,解析测试环境对应的数据文件内容:URL(get_url)、账号(get_user)、数据库配置(get_db),同时传递给api类(api_module_A…B…C)、登录方法(login)、数据库连接方法(use_db)等,用于实例化操作,这部分fixture函数再传递给测试用例,用于用例前后置操作(相当于setup/teardown);

最后测试用例再根据各个fixture函数返回的实例对象、配置信息,调用各个模块的api函数,执行测试,并读写数据库实现数据校验、断言,从而最终实现切换环境策略;

3、目录结构&框架设计小技巧

目录结构:
项目结构大致如下,至于目录结构和文件命名,只能说萝卜青菜各有所爱。比如有人喜欢把存放公共方法的common目录命名为utils,存放各个api模块的api目录命名为src…

C2

自动化测试框架设计小技巧:
api:存放封装各个项目、各个模块的api,如jk项目支付模块,可以命名为jk_pay.py;
config:存放配置文件,直接用py文件即可,不推荐使用ini、yaml,反而会多了一层解析,增大出错概率;

common:存放公共方法,如基于http协议requests库,则可以命名为http_requests.py;通过文件名称,大概率就能知道这个文件的作用,比如通过parse_excel的命名直接就能知道是解析excel文件;

main:框架主入口,存放用来批量执行用例的文件,比如:run_testcase_by_tag.py(前提是用例都打了标签)、run_testcase_by_name.py;
fixture:存放fixture文件,建议每个项目一个fixture文件,互不影响,如:jk_fixture.py、jc_fixture.py;
test_case:存放测试用例文件;

conftest.py:存放一些hook函数、全局fixture函数,如前面提到的自定义命令行参数的函数pytest_addoption、获取命令行参数的fixture函数get_env;
pytest.ini:pytest框架配置文件;

4、实现过程

上述的方案单从文字层面可能有些难以理解,下面我们结合具体的代码案例来详细讲述一下实现过程。

实现自定义命令行参数工具:
在conftest.py中定义一个hook函数,实现自定义命令行工具,名为pytest_addoption(固定写法),用来在命令行中传入不同的环境参数;

def pytest_addoption(parser):"""添加命令行参数parser.addoption为固定写法default 设置一个默认值,此处设置默认值为testchoices 参数范围,传入其他值无效help 帮助信息"""parser.addoption("--env", default="test", choices=["dev", "test", "pre"], help="enviroment parameter")

定义获取命令行参数的fixture函数:
在conftest.py中定义get_env的fixture函数,用来获取用户在命令行输入的参数值,传递给fixture.py中的各个fixture函数。pytestconfig是request.config的快捷方式,所以request.config也可以写成pytestconfig。

@pytest.fixture(scope="session")
def get_env(request):return request.config.getoption("--env")

来测试一下命令行能否输入参数以及fixture函数get_env能否获取到。我们可以简单定义一个测试用例:

def test_env(get_env):print(f"The current environment is: {get_env}")

然后通过命令行执行此测试用例:

pytest -s -v --env dev test_env.py::test_env

执行结果如下:

C3

定义环境解析策略:
例如当前项目为jc项目,则可以在fixture目录下定义一个jc_fixture.py的文件,用于专门存放此项目相关的fixture函数。

fixture.py中的各个fixture函数根据get_env提供的环境参数值,解析测试环境对应的数据文件内容:URL(get_url)、账号(get_user)、数据库配置(get_db),同时传递给api类(api_module_A…B…C)进行实例化,登录方法(login)、数据库连接方法(use_db)等,进行初始化,这部分fixture函数再传递给测试用例,用于用例前后置操作(相当于setup/teardown);

import pytest
from config.config import URLConf, PasswordConf, UsernameConf, ProductIDConf
from api.jc_common import JCCommon
from api.jc_resource import JCResource
from config.db_config import DBConfig
from common.mysql_handler import MySQL@pytest.fixture(scope="session")
def get_url(get_env):"""解析URL"""global urlif get_env == "test":print("当前环境为测试环境")url = URLConf.RS_TEST_URL.valueelif get_env == "dev":print("当前环境为开发环境")url = URLConf.RS_DEV_URL.valueelif get_env == "pre":print("当前环境为预发布环境")url = URLConf.RS_PRE_URL.valuereturn url@pytest.fixture(scope="session")
def get_user(get_env):"""解析登录用户"""global username_admin, username_boss# 若get_env获取到的是test,则读取配置文件中测试环境的用户名if get_env == "test":username_admin = UsernameConf.RS_TEST_ADMIN.valueusername_boss = UsernameConf.RS_TEST_BOSS.value# 若get_env获取到的是dev,则读取配置文件中开发环境的用户名elif get_env == "dev":username_admin = UsernameConf.RS_TEST_ADMIN.valueusername_boss = UsernameConf.RS_TEST_BOSS.value# 若get_env获取到的是pre,则读取配置文件中预发布环境的用户名elif get_env == "pre":username_admin = UsernameConf.RS_TEST_ADMIN.valueusername_boss = UsernameConf.RS_TEST_BOSS.value@pytest.fixture(scope="session")
def get_db(get_env):"""解析数据库配置"""global db_host, db_pwd, db_ssh_host, db_ssh_pwd, db_nameif get_env == "test":db_host = DBConfig.db_test.get('host')db_pwd = DBConfig.db_test.get('pwd')db_ssh_host = DBConfig.db_test.get('ssh_host')db_ssh_pwd = DBConfig.db_test.get('ssh_pwd')db_name = DBConfig.db_test.get('dbname_jc')elif get_env == "dev":db_host = DBConfig.db_test.get('host')db_pwd = DBConfig.db_test.get('pwd')db_ssh_host = DBConfig.db_test.get('ssh_host')db_ssh_pwd = DBConfig.db_test.get('ssh_pwd')db_name = DBConfig.db_test.get('dbname_jc')elif get_env == "pre":db_host = DBConfig.db_test.get('host')db_pwd = DBConfig.db_test.get('pwd')db_ssh_host = DBConfig.db_test.get('ssh_host')db_ssh_pwd = DBConfig.db_test.get('ssh_pwd')db_name = DBConfig.db_test.get('dbname_jc')@pytest.fixture(scope="session")
def jc_common(get_env, get_url):"""传入解析到的URL、实例化jc项目公共接口类"""product_id = ProductIDConf.JC_PRODUCT_ID.valuejc_common = JCCommon(product_id=product_id, url=get_url)return jc_common@pytest.fixture(scope="session")
def jc_resource(get_env, get_url):"""传入解析到的URL、实例化jc项目测试接口类"""product_id = ProductIDConf.JC_PRODUCT_ID.valuejc_resource = JCResource(product_id=product_id, url=get_url)return jc_resource@pytest.fixture(scope="class")
def rs_admin_login(get_user, jc_common):"""登录的fixture函数"""password = PasswordConf.PASSWORD_MD5.valuelogin = jc_common.login(username=username_shipper, password=password)admin_user_id = login["b"]return admin_user_id@pytest.fixture(scope="class")
def jc_get_admin_user_info(jc_common, jc_admin_login):"""获取用户信息的fixture函数"""user_info = jc_common.get_user_info(user_id=rs_shipper_login)admin_cpy_id = user_info["d"]["b"]return admin_cpy_id@pytest.fixture(scope="class")
def use_db(get_db):"""链接数据库的fixture函数"""mysql = MySQL(host=db_host, pwd=db_pwd, ssh_host=db_ssh_host, ssh_pwd=db_ssh_pwd, dbname=db_name)yield mysqlmysql.disconnect()

测试用例引用fixture:
封装各个待测模块的api函数
登录模块:jc_common.py

from common.http_requests import HttpRequestsclass JcCommon(HttpRequests):def __init__(self, url, product_id):super(JcCommon, self).__init__(url)self.product_id = product_iddef login(self, username, password):'''用户登录'''headers = {"product_id": str(self.product_id)}params = {"a": int(username), "b": str(password)}response = self.post(uri="/userlogin", headers=headers, params=params)return responsedef get_user_info(self, uid, token):'''获取用户信息'''headers = {"user_id": str(uid), "product_id": str(self.product_id), "token": token}response = self.post(uri="/user/login/info", headers=headers)return response

业务模块:jc_resource.py

import random
from common.http_requests import HttpRequests
from faker import Fakerclass RSResource(HttpRequests):def __init__(self, url, product_id):super(RSResource, self).__init__(url)self.product_id = product_idself.faker = Faker(locale="zh_CN")def add_goods(self, cpy_id, user_id, goods_name, goos_desc='', goods_type='', goos_price=''):"""新增商品"""headers = {"product_id": str(self.product_id), "cpy_id": str(cpy_id), "user_id": str(user_id)}params = {"a": goods_name, "b": goos_desc, "c": goods_type, "d": goos_price}r = self.post(uri="/add/goods", params=params, headers=headers)return rdef modify_goods(self, cpy_id, user_id, goods_name, goos_desc='', goods_type='', goos_price=''):"""修改商品信息"""headers = {"product_id": str(self.product_id), "cpy_id": str(cpy_id), "user_id": str(user_id)}params = {"a": car_name, "ab": car_id, "b": company_id, "c": car_or_gua}r = self.post(uri="/risun/res/car/add/blacklist?md=065&cmd=006", params=params, headers=headers)return r

各个模块的api函数作为独立的存在,将配置与函数隔离,且不涉及任何fixture的引用。这样无论测试URL、用户名、数据库怎么变换,也无需修改待测模块的api函数,基本可以做到一劳永逸,除非接口地址和传参发生变化。

测试用例:
JC项目的测试用例类TestJcSmoke根据各个jc_fixture.py中各个fixture函数返回的实例对象、配置信息,调用各个业务模块的api函数,执行测试,并读写数据库实现数据校验、断言;

import os
import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))))
import allure
from fixture.jc_fixture import *
from common.parse_excel import ParseExcellogger = LogGen("JC接口Smoke测试").getLog()@allure.feature("JC项目接口冒烟测试")
class TestJcSmoke:def setup_class(self):self.fake = Faker("zh_CN")# 将fixture中的jc_resource实例、数据库实例、登录等fixture函数传递给测试用例进行调用@pytest.mark.jc_smoke@allure.story("商品管理")def test_01_goods_flow(self, jc_resource, jc_admin_login, jc_get_admin_user_info, use_db):"""测试商品增删改查接口"""user_id = jc_admin_logincpy_id = jc_get_admin_user_infogoods_name = "iphone 14pro max 512G"try:logger.info(f"新增'{goods_name}'商品")with allure.step("调用添加商品接口"):add_goods = jc_resource.add_goods(cpy_id, user_id, goods_name, goods_type=1)assert add_goods["a"] == 200self.goods_id = add_goods["d"]select_db = use_db.execute_sql(f"SELECT * FROM goods_info WHERE company_id = {cpy_id} AND id = {self.goods_id}")  # 查询数据库是否存在新增的数据assert goods_name in str(select_db)logger.info(f"商品'{goods_name}'新增成功")logger.info(f"修改'{goods_name}'的商品信息")with allure.step("调用修改商品接口"):modify_goods = jc_resource.modify_goods(cpy_id, user_id, goods_id=self.goods_id, goods_name=goods_name, goods_type=2)assert modify_goods["a"] == 200select_db = use_db.execute_sql(f"SELECT goodsType FROM goods_info WHERE company_id = {cpy_id} AND id = {self.goods_id}")assert str(select_db[0]) == '2'logger.info(f"修改'{goods_name}'的商品信息成功")logger.info(f"开始删除商品'{goods_name}'")with allure.step("调用删除商品接口"):del_goods = jc_resource.delete_goods(cpy_id, user_id, goods_id=self.goods_id)assert del_goods["a"] == 200select_db = use_db.execute_sql(f"SELECT * FROM goods_info WHERE id = {self.goods_id}")print(select_db)logger.info(f"删除商品'{goods_name}'成功")except AssertionError as e:logger.info(f"商品流程测试失败")raise e

在上述smoke测试用例test_01_goods_flow中,同时验证了商品的增、改、删三个接口,形成一个简短的业务流,如果接口都是畅通的话,则最后会删除商品,无需再手动维护。

注意:
上述模块接口及测试用例仅为演示使用,非真实存在。

传统的测试用例设计模式中,会把一些实例化放在setup或setup_class中,如:jc_resource = JcResource(xxx),但因为fixture函数无法在前后置方法中传递的缘故,所以要把一些实例化的操作放在fixture函数中进行,并return一个内存地址,直接传递给测试用例,从而使测试用例能够调用到实例对象中的业务api。

5、运行项目

完成了命令行参数、解析策略、封装接口、测试用例编写后,既可以直接在编辑器中点击运行按钮执行测试,也可以在命令行驱动执行。以下演示命令行执行用例方法:

-v:打印详细执行过程;
-s:控制台输出用例中的print语句;
–env:前面pytest_addoption定义的命令行参数,默认值:test,输入范围choices=[“dev”, “test”, “pre”]

输入一个不存在的–env参数

pytest -v -s --env online test_jc_smoke.py

此时会提示我们参数错误,online为不可用选项。

C4

运行测试环境

pytest -v -s --env test test_jc_smoke.py

为了方便起见,直接运行了现有项目的测试用例,当传入test时,会在测试环境运行。

C5

一共12条测试用例,全部运行通过:

C6

同时,测试结果发送到企业微信群。

C7

运行开发及预发布环境

pytest -v -s --env dev test_jc_smoke.py  # 开发环境
pytest -v -s --env pre test_jc_smoke.py  # 预发布环境

dev、pre参数接收正常,不过因为开发、预发布环境没启动的缘故,所以执行失败。

C8

C9

6、Pytest实现一键切换环境方案原理小结

原理说明:
测试环境变量由用户输入提供;
测试框架定义测试数据解析函数,并根据用户输入的测试变量,解析并返回测试环境对应的数据文件内容;

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

一、Python编程入门到精通

请添加图片描述

二、接口自动化项目实战

请添加图片描述

三、Web自动化项目实战

请添加图片描述

四、App自动化项目实战

请添加图片描述

五、一线大厂简历

请添加图片描述

六、测试开发DevOps体系

请添加图片描述

七、常用自动化测试工具

请添加图片描述

八、JMeter性能测试

请添加图片描述

九、总结(尾部小惊喜)

只要朝着目标坚定前行,努力不息,困难会变得渺小,成功将变得触手可及。不要追求一夜成名,而是坚持积累与进步,你一定能够创造出属于自己的辉煌!相信自己,勇敢拼搏,未来由你决定!

不管前方多漫长多曲折,只要你有一颗不服输的心,永不言弃的精神,努力奋斗,你就能找到属于自己的道路并取得成功。相信自己的能力,坚持追逐梦想,未来将为你绽放光芒!

即使身处黑暗的时刻,也要保持信念与毅力,勇往直前,坚定不移地追求梦想。每一次努力都是积累,每一次坚持都是成长,只要不停止奋斗,成功的曙光终将到来!相信自己,敢于冒险,创造属于自己的辉煌!加油!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/5305.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LangChain大型语言模型(LLM)应用开发(五):评估

LangChain是一个基于大语言模型(如ChatGPT)用于构建端到端语言模型应用的 Python 框架。它提供了一套工具、组件和接口,可简化创建由大型语言模型 (LLM) 和聊天模型提供支持的应用程序的过程。LangChain 可以轻松管理与语言模型的交互&#x…

ceph应用

资源池 Pool 管理 上面我们已经完成了 Ceph 集群的部署,但是我们如何向 Ceph 中存储数据呢?首先我们需要在 Ceph 中定义一个 Pool 资源池。Pool 是 Ceph 中存储 Object 对象抽象概念。我们可以将其理解为 Ceph 存储上划分的逻辑分区,Pool 由多…

Qt6 Qt Quick UI Prototype学习QML第一篇

Qt6 Qt Quick UI原型学习QML第一篇 开始创建项目Qt Quick UI原型简介.qmlproject文件举例Window平台小例子运行效果QML语法 了解语法 开始创建项目 创建一个具有QML入口点的Qt Quick 2 UI项目。要使用它,您需要设置一个QML运行时环境,例如gmlscene。 仅当…

消息队列——rabbitmq的不同工作模式

目录 Work queues 工作队列模式 Pub/Sub 订阅模式 Routing路由模式 Topics通配符模式 工作模式总结 Work queues 工作队列模式 C1和C2属于竞争关系,一个消息只有一个消费者可以取到。 代码部分只需要用两个消费者进程监听同一个队里即可。 两个消费者呈现竞争关…

安全防御 --- DDOS攻击(01)

DOS攻击(deny of service)--- 拒绝式服务攻击 例:2016年10月21日,美国提供动态DNS服务的DynDNS遭到DDOS攻击,攻击导致许多使用DynDNS服务的网站遭遇访问问题,此事件中,黑客人就是运用了DNS洪水…

golang waitgroup

案例 WaitGroup 可以解决一个 goroutine 等待多个 goroutine 同时结束的场景,这个比较常见的场景就是例如 后端 worker 启动了多个消费者干活,还有爬虫并发爬取数据,多线程下载等等。 我们这里模拟一个 worker 的例子 package mainimport (…

ChatGPT与Claude对比分析

一 简介 1、ChatGPT: 访问地址:https://chat.openai.com/ 由OpenAI研发,2022年11月发布。基于 transformer 结构的大规模语言模型,包含1750亿参数。训练数据集主要是网页文本,聚焦于流畅的对话交互。对话风格友好,回复通顺灵活,富有创造性。存在一定的安全性问题,可…

【深度学习】基于BRET的高级主题检测

一、说明 使用BERT,UMAP和HDBSCAN捕获文档主题,紧随最先进的BERTopic架构(transformer编码器)。 主题检测是一项 NLP 任务,旨在从文本文档语料库中提取全局“主题”。例如,如果正在查看书籍描述的数据集,主题检测将使我们能够将书籍分类,例如:“浪漫”、“科幻”、“旅…

Springboot+Flask+Neo4j+Vue2+Vuex+Uniapp+Mybatis+Echarts+Swagger综合项目学习笔记

文章目录 Neo4j教程:Neo4j高性能图数据库从入门到实战 医疗问答系统算法教程:医学知识图谱问答系统项目示例:neo4j知识图谱 Vueflask 中药中医方剂大数据可视化系统可视化技术:ECharts、D.jsflask教程:速成教程Flask w…

list模拟实现

一、结点的定义 有三个成员&#xff0c;2个指向前面和后面的指针&#xff0c;一个表示结点存储T类型的值。 对于_prev和_next&#xff0c;类型是 list_node<T>*&#xff0c;不是list_node*&#xff0c;加上类型参数T之后&#xff0c;才是模板类的类型。 构造函数中&am…

【MySQL】MySQL8.1.0版本正式发布带来哪些新特性?

文章目录 前言一、畅谈新版本二、8.1.0版本部署2.1、环境准备2.2、配置yum安装依赖2.3、用户及目录创建2.4、创建用户及组2.5、解压缩包2.6、环境变量配置2.7、创建参数文件2.8、数据库初始化2.9、启动Mysql2.10、登陆MySQL 8.1 三、新特性3.1、密码参数3.2、错误日志加强3.3、…

Spring Security OAuth2.0(6):自定义认证自定义登录页

文章目录 自定义登录界面配置自定义登录页面 自定义登录界面 \qquad 你可能想知道登录页面从哪里来&#xff1f;因为我们并没有提供任何的HTML或JSP文件。Spring Security 的默认配置没有明确设定一个登录页面的URL&#xff0c;因此Spring Security 会根据启用的功能自动生成一…

Godot实用代码-存取存档的程序设计

1. Settings.gd 全局变量 用于保存玩家设置 对应Settings.json 2. Data.gd 全局变量 用于保存玩具数据 对应Data.json 实践逻辑指南 1.在游戏开始的时候&#xff08;游戏场景入口的_ready()处&#xff0c; Settings.gd

Linux内核结构与特性简介

系统调用接口&#xff1a;位于最上层&#xff0c;实现了一些基本的功能&#xff0c;如read和write等系统调用。这是用户空间程序与内核交互的接口&#xff0c;提供了对内核功能的访问。 内核代码&#xff1a;位于系统调用接口之下&#xff0c;可以看作是独立于体系结构的通用内…

qt和vue交互

1、首先在vue项目中引入qwebchannel /******************************************************************************** Copyright (C) 2016 The Qt Company Ltd.** Copyright (C) 2016 Klarlvdalens Datakonsult AB, a KDAB Group company, infokdab.com, author Milian …

13_Linux无设备树Platform设备驱动

目录 Linux驱动的分离与分层 驱动的分隔与分离 驱动的分层 platform平台驱动模型简介 platform总线 platform驱动 platform设备 platform设备程序编写 platform驱动程序编写 测试APP编写 运行测试 Linux驱动的分离与分层 像I2C、SPI、LCD 等这些复杂外设的驱动就不…

Fortinet Accelerate 2023·中国区巡展收官丨让安全成就未来

7月18日&#xff0c;2023 Fortinet Accelerate Summit在上海成功举办&#xff01;这亦象征着“Fortinet Accelerate2023中国区巡展”圆满收官。Fortinet携手来自多个典型行业的百余位代表客户&#xff0c;以及Telstra - PBS 太平洋电信、Tenable等多家生态合作伙伴&#xff0c;…

利用数据分析告警机制,实现鸿鹄与飞书双向集成

需求描述 实现鸿鹄与飞书的双向集成&#xff0c;依赖鸿鹄的告警机制&#xff0c;可以发送用户关心的信息到飞书。同时依赖飞书强大的卡片消息功能&#xff0c;在飞书消息里面能够通过链接&#xff08;如下图&#xff09;返回到鸿鹄以方便用户进一步排查和分析问题。 解决方案 1…

CGT Asia嘉年华|2023第四届亚洲细胞与基因治疗 创新峰会(广州站)10月升级启航

近年来&#xff0c;全球CGT发展突飞猛进&#xff0c;为遗传罕见病、难治性慢性病和肿瘤患者带来了新的希望&#xff0c;也成为整个国际领域科技竞争的未来焦点。国家发改委发布的《“十四五”生物经济发展规划》明确指出要重点发展基因诊疗、干细胞治疗、免疫细胞治疗等新技术&…

利用鸿鹄优化共享储能的SCADA 系统功能,赋能用户数据自助分析

摘要 本文主要介绍了共享储能的 SCADA 系统大数据架构&#xff0c;以及如何利用鸿鹄来更好的优化 SCADA 系统功能&#xff0c;如何为用户进行数据自助分析赋能。 1、共享储能介绍 说到共享储能&#xff0c;可能不少朋友比较陌生&#xff0c;下面我们简单介绍一下共享储能的价值…