常见测试方法详解
【摘要】 常见测试方法详解
API 接口测试
概念和测试重点
- API 接口测试是测试系统组件间接口的一种测试
- 包含两种测试场景
- 系统与外部其他系统之间的接口
- 系统内部各个子模块(子系统)之间的接口
- API 接口测试重点
- 检查接口参数传递的正确性
- 接口功能实现的正确性
- 输出结果的正确性
- 对各种异常情况的容错处理的完整性和合理性
API 接口测试分类
- 单 API 接口测试:针对单个 API 接口的测试场景,主要关注
参数取值
和参数取值组合
- 组合 API 接口测试:把多个 API 的逻辑串联起来测试,主要关注
功能的完整性和正确性
- 完整性:完成一个特定的功能
- 正确性:通过组合调用多个接口,完成一个业务逻辑后,要关注执行结果的正确,满足业务测试要求
API 接口测试面临的挑战
- 随着微服务架构的流行,微服务开发迭代周期短、版本多,单个微服务需要具备独立测试和快速验证的能力,以支持测试活动前移。目前,主要面临如下两个挑战:
- 服务不具备独立验证能力
- 传统的技术架构使大量测试活动在集成测试等阶段进行验证,而微服务需要独立测试能力,通过测试活动前移,提前发现问题,从而保证版本质量
- 自动化用例开发效率很低
- 传统的技术框架自动化用例开发效率低,无法满足用例快速增长的需求,自动化用例开发存在效率瓶颈
- 服务不具备独立验证能力
API 接口测试的三原则
- 同源:同源是指设计、开发、测试三个活动基于同一个源头开展(最好是基于
完备的API定义文档
) - 独立测试:DevOps 模式下,微服务需要具备独立测试的能力,而50%以上的服务都涉及到服务之间的依赖,必须通过 Mock 等技术才能使环境解耦,否则微服务独立测试很难开展
- 100%自动化测试:在开发自测阶段,为了提高测试效率,快速得到测试结果,应尽量高效使用自动化测试,倡议是100%的自动化
API 接口测试的设计过程
- 接口梳理:是参考接口设计文档、业务流图等梳理出我们要测试的所有接口
- API接口参数分析:熟悉接口参数类型和每一个参数的作用
- 业务场景梳理:理开展业务场景分析,分析出设计的API组合、业务逻辑之间的关联关系等
- 单接口测试设计:单接口单参数取值,单接口多参数组合,测试输入数据设计、返回检查点设计等
- 多接口组合场景设计:多接口组合调用,还原真实的业务场景
API 接口测试自动化流程
- 接口分析:参考接口设计文件,进行接口分析
- 用例设计:进行接口用例设计
- 接口封装:对接口调用进行封装
- 用例生成:开发接口用例脚本
- 用例执行:执行接口自动化用例
API 接口自动化测试(华为云)
- AW: Action Word,也可理解为关键字,可复用的执行逻辑单元,方便自动化脚本扩展和复用
- AW自动生成与共享:根据接口定义文档,或者是叫 YAML 文档,根据 YMAL 文档快速自动生成 AW,且能在不同微服务间实现 AW 的共享
性能测试
性能测试的重要性
- 应用出现性能问题,不仅仅是用户体验的损失,而是会产生不可挽回的经济损失
- Amazon 的统计显示客户访问的
响应时间每延长1s,Amazon 一年就会减少16亿美元销售额
,首页打开时间每增加100ms,网站的销售量会减少1% - 据统计,每年电子商务网站都会因载入速度过慢,而
损失11亿~13亿美元
的收入 - 响应速度在 Google 的 PR(PageRank) 评分中占有一定的比例,也就是说,一个好的网站是不可能让他的页面加载速度很慢的
- Amazon 的统计显示客户访问的
各行各业面临的典型性能问题
- 性能问题会严重影响用户体验,导致用户流失
性能测试内容
- 负载测试(load test):对于分布式网络,测试不同用户数量来测试系统的反应,主要关注性能指标,系统不同表现
- 压力测试(stress testing):高压状态下多用户高并发测试(30万-50万),主要关注系统是怎么崩溃的(内存泄漏,cpu无响应,数据库无反应,网络堵塞)
- 容量测试(volumn testing):系统最大支撑的相关数量,数据库最大数据数量,用户数量
性能测试评价指标
- 响应时间(response time):从用户视角评价系统的响应速度,通常响应的时间的经验值 2s流畅,5s可用,8s较慢
- 吞吐量/率:硬盘IO(读写),网络IO(上行下行带宽),cupIO,服务器处理能力,客户端打开页面的数量。
- 事务处理能力(TPS tansaction per second):打开页面,登陆服务器,实现消息发送等等用户的某一动作就被称为事物
性能测试关注点
- 响应时间快慢,服务器端的处理速度
- 服务器端的使用情况
- 数据库端的资源使用情况
- 最大用户访问数量
- 同时处理最大业务数量
- 考察系统能否支撑 7x24 小时运转
- 内存资源、线程资源能否正常回收
- 代码,算法,SQL 语句设计是否合理
- 整个系统的稳定性,可恢复性
性能测试的核心原理
- 基于协议(前端后端通信机制),基于界面(决定和前端交互),基于代码(后端)。
- 基于网络的分布式架构:基于网络协议去模拟用户发送请求
- 多线程:模拟多线程操作,多人同时操作,模拟大负载量(功能测试在于用以测试功能)
- 模拟真实场景:真实的网络环境,用户操作时间不确定性,操作不确定,得出的数据是准确的,场景不对,数据也不一定可用
从传统的性能测试活动看云化挑战
- 传统的性能测试有如下两个痛点
- 工具链复杂:从环境准备到测试执行到问题定位都非常耗时,往往需要数周时间才能完成一次性能测试
- 人员要求高:开源工具门槛很高,测试模型设计和测试用例编写需要对工具非常的熟悉,性能问题的定位更是需要测试人员有丰富的性能测试经验
- 总而言之就是:不够快,不会测,难定位,传统性能测试工具链无法满足当前云化系统的测试需求
华为 CPTS 云性能测试服务设计理念 —— Anyone/ Anywhere/ Anytime
CPTS 服务一站式云化性能测试解决方案
CPTS优点 —— 免编码全 UI 操作
- 云容器引擎(CCE)
- 云容器引擎(Cloud Container Engine,简称CCE)提供高度可扩展的、高性能的企业级Kubernetes集群,支持运行Docker容器,提供了Kubernetes集群管理、容器应用全生命周期管理、应用服务网格、Helm应用模板、插件管理、应用调度、监控与运维等容器全栈能力,为您提供一站式容器平台服务。借助云容器引擎,您可以在华为云上轻松部署、管理和扩展容器化应用程序
- 云容器实例(CCI)
- 云容器实例(Cloud Container Instance, CCI)服务提 Serverless Container(无服务器容器)引擎,让您无需创建和管理服务器集群即可直接运行容器。通过CCI您只需要管理运行在Kubernetes上的容器化业务,无需管理集群和服务器即可在CCI上快速创建和运行容器负载,使容器应用零运维,使企业聚焦业务核心,为企业提供了Serverless化全新一代的体验和选择
- 而Serverless是一种架构理念,是指不用创建和管理服务器、不用担心服务器的运行状态(服务器是否在工作等),只需动态申请应用需要的资源,把服务器留给专门的维护人员管理和维护,进而专注于应用开发,提升应用开发效率、节约企业IT成本。传统上使用 Kubernetes 运行容器,首先需要创建运行容器的 Kubernetes 服务器集群,然后再创建容器负载
契约测试(Mock 测试)
契约测试的背景
- Microservice 是一种架构风格,它将单个的应用设计成一组服务的集合
- 优点
- 高度模块化
- 可独立部署
- 技术多样性
- 痛点
- 分布式
- 最终一致性
- 管理复杂性
微服务如何测试
- 如上述图表示某个微服务被其他多个微服务依赖和调用(中间的微服务被周边众多服务依赖和互相调用),如何保证该微服务的修改不会对其他所有调用者造成影响呢?答案就是
契约测试
什么是契约测试(Contract Testing)
- 契约测试是一种
针对外部服务的接口进行的测试
,它能够验证服务是否满足消费方期待的契约。这个契约包含了对输入和输出的数据结构的期望,性能以及并发性
- Consumer(消费者):Service 的使用者,向 Provider 发起 HTTP 请求来获取数据
- Provider(生产者):Service 的提供者,接受 Consumer 的 HTTP 请求并返回数据
- Contract(契约):一种定义在 Consumer 和 Provider 之间的交互方式(请求和相应的过程就通过契约固化下来)
为什么要开展契约测试
- 3个 Consumer 对 Provider 有依赖,而且依赖的需求不一样,契约是对3个 Provider 的请求的汇总之和
- 契约测试是验证 Provider 是否按照期望的方式与 Consumer 进行交互,是为 Consumer 驱动提供质量保证
契约测试的实践方式
-
产品环境(消费者与生产者的调用关系)
-
测试环境
-
通过
Mock
技术解除 Consumer 对 Provider 的依赖 -
达通过
契约测试
保证 Provider 的修改对 Consumer 保持一致
使用 Contract 来验证 Provider
- 上图表达在产品环境下,一个微服务同时被多个使用者调用,如何保证对于该微服务的修改不会对其他所有使用者造成影响?
- 上图是在测试环境下的解决方案,在 Provider 的测试环境下,通过契约(Contract)模拟真实的 Consumer,从而保证 Provider 的修改不会造成任何契约失效,即 Contract 模拟了周边的这些微服务的调用
Mock 测试
Mock 测试的概念
- Mock 测试就是在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个虚拟的对象来创建以便测试的测试方法
- Mock 测试主要是接触微服务间的依赖,从而支撑服务快速测试(快速上线)
Mock 测试的目标
- 实现服务解耦:通过 Mock 解除对其他服务的依赖
- 分层测试,自动化一切:微服务接口测试,服务组集成测试,场景测试等
- 精准测试:通过 Mock 技术精准模拟其他服务的返回
- Mock 自服务(YAML 同源):将服务自己对外提供的接口 Mock 化,从而达到与yaml(API 接口定义文档)同源
云测 Mock 优秀实践
- APImanager 通过 yaml 文件来对 API 接口进行定义
- 当yaml文件变更(API接口有变更),Mock 服务感知到后,通过 Mock 流水线,自动升级部署 Mock 实例
WebUI 测试
WebUI 测试的场景
- 冒烟测试(主业务流程)
- 新功能测试
- 回归测试
- 兼容测试(一套测试脚本,多个浏览器执行)
- 完成手动测试无法完成的工作下班后无人值守测试
- 新功能测试是因为需求不稳定、变化比较多不太适合进行自动化测试
回归测试
和兼容性测试
,前者执行了大量的回归测试用例,后者需要这些用例在不同浏览器里面重复执行。那么完全可以利用自动化的方式将这些重复、低效易错的工作变得更加高效,从而节约人力成本
Web 自动化测试优点
- 更快的测试速度
- 带来更高的测试效率。一般而言,运行一遍功能测试都要以
小时
为单位,有的甚至以天
为单位。而自动化测试则一般都在分钟
级别,如果运行在分布式环境下,甚至可以降到秒级
- 带来更高的测试效率。一般而言,运行一遍功能测试都要以
- 更高的测试覆盖率
- 测试场景越复杂,所需的测试用例越多。当测试场景的复杂度超过一定程度后,纯手工的功能测试显然就无力覆盖所有的测试功能了,并且随着复杂度的提高,测试覆盖率会越来越低
- 更好的稳定性和可扩展性
- 功能测试
靠人
,自动化测试靠机器
,因此,无论运行测试的稳定性,还是测试能力的可扩展性(比如从测试1个应用变为测试10个应用),显然自动化测试优于人工测试
- 功能测试
比如我们做完 WebUI 的测试后发现要对不同浏览器做重复的测试,如果是通过人工测试的话,然后做自动化测试,部署了一些脚本在某一个真机上面,从而驱动脚本在不同浏览器下做自动化测试,完全可以做到下班之前把脚本挂上,然后第二天早上过来看这个脚本执行结果,从而解放测试的人工时间
Selenium + TestNG 的 WebUI 自动化框架
- 测试和编写业务逻辑
- 编写配置文件
testng.xml
- 运行 TestNG 类型的工程
- DataProvider:DataProvider 使得对同一个方法的测试覆盖变的非常轻松,非常适合进行边界测试,只要给出多种测试数据就可以针对一个测试方法进行覆盖
- Base Case:提供基础的方法和框架
- 结果报表:运行 TestNG,TestNG 默认情况下,会生产两种类型的测试报告
HTML
的和XML
的。 测试报告位于"test-output"
目录下 - 结果校验库:执行过程中添加检查点进行校验
- UI Map:生成脚本必须的Map文件
- 业务封装库:封装成共有的方法
- 日志库:执行日志
云测 —— 一站式 Web 全自动化测试解决方案
- Selenium+TestNG需要基本的编程经验,需要查阅大量API说明,不太适合手工测试人员快速上手
- DevCloud 的 Web 自动化满足了手工测试人员期望 “不用编码就能实现 Web 自动化测试”
- 具体方案如下
- 手工操作一遍,工具自动记录测试脚本
- 通过图像化的脚本编排,提取测试步骤共有的 Keyword
- 基于 Selenium+TestNG 的执行框架进行回放执行
- 接入工厂实现脚本自动执行、测试结果上报和生成测试报告
可靠性与安全测试
软件可靠性定义和方法
- 软件可靠性是指软件在所规定的环境条件下和规定的时间内正确地完成任务的能力
- 可靠性测试方法主要有两种类型
- 基于操作剖面开展测试
- 按照软件操作剖面对软件进行随机测试的测试方法
- 根据软件在客户实际使用过程的各种操作的使用概率选择操作剖面,对软件系统进行可靠性测试
- 基于故障注入开展测试
- 故障注入是按照选定的故障模型,采用人工的方法将故障注入到特定的目标系统中,同时采集系统对所注入故障的反应信息,通过这些信息对系统进行可靠性分析
- 基于操作剖面开展测试
软件故障注入技术
- 与其他可靠性评价技术相比,故障注入方法能方便灵活、便捷有效地处理各种可靠性问题,得到了越来越多的关注。故障注入技术有模拟实现的故障注入、硬件实现的故障注入和软件实现的故障注入三种
- 软件故障注入
- 是通过修改
硬件或软件的状态变量或相关数据
来模拟故障的产生,加速系统的失效,分为静态注入和动态注入两种类型
- 是通过修改
- 静态故障注入
- 主要通过程序变异的方法,通过
改变原程序
,使被测系统文件静态的存在错误,从而使其运行时出现故障。静态注入占用很少的系统资源,能够较好地保持系统原来的时序,这种注入法有很好的优化性
- 主要通过程序变异的方法,通过
- 动态注入
- 是在
被测系统正常运行过程中
,实现故障注入。该种方式是根据被测系统的运行状态或条件注入故障的,具有灵活性
- 是在
- 软件故障注入
可靠性设计 —— 测试指标
.类别 | 关注灾难场景 | 指标 | 描述 | 测试/运维活动 |
数据可靠性 | 运维误操作或基础平台问题造成数据大量丢失 | 数据恢复用时(RTO) | 从数据丢失开始,到数据恢复的时间 | 数据恢复演练 |
数据恢复点(RPO) | 数据丢失后,能够保证数据恢复到之前的某个时间点 | 定时备份、每日备份巡检 | ||
系统可用性 | 单点故障对业务的影响: 虚拟机或容器下电; 虚拟机重启; 网络闪断、中断; 进程异常退出; 资源类:CPU、内存占用率高; .... |
故障检测时间 | 从故障发生,到系统检测到故障的时间,比如 HA 对后端健康检查的频率 | 单节点故障下的高可用测试 |
故障隔离时间 | 从故障发生到系统管理节点隔离故障的时间,比如 HA 隔离后端掉线节点的时间 | 单节点故障下的高可用测试 | ||
故障定位时间 | 从故障发生到检测告警平台发现并定位到最小故障单元(如进程)的时间 | 监控告警测试 | ||
故障恢复时间 | 单节点故障能够自动或手动被恢复的时间 | 单节点故障下的高可用测试 | ||
升级部署 | 升级时业务中断 | 上线、升级时间 | 从提交代码到完成部署的时间 | 升级流水线测试 |
升级中断时间 | 升级过程中业务中断的时间 | 升级中断测试 | ||
业务可用度 | 现网业务异常 | 业务可用度 | 全年内业务可用的时间百分比,业界一般为3个9到4个9 | 现网拨测 |
可靠性测试 —— Chaos 混沌测试
- 微服务的故障给公司造成巨大损失,也给用户带来很大的麻烦,影响他们进行在线购物、交易或打断他们的工作。即使是一些简单的故障也会触及公司的底线,因此,宕机时间就成为很多工程团队的 KPI
- 2017 年,有 98% 的企业表示,一小时的宕机时间将给他们带来超过 10 万美元的损失。一次服务中断有可能让一个公司损失数百万美元。英国航空的 CEO 透露,2017 年 5 月发生的一次技术故障造成数千名乘客滞留机场,给公司造成 8000 千万英镑的损失。2008年,Netflix也开始从数据中心迁移到云上,然后开展一些系统的弹性的测试,这个实践过程被称为
混沌测试
。这就是最开始 “Chaos Monkey” 的一个混沌测试的原型
在线测试
为什么要做在线测试
- 为什么要做在线测试?
- 在线测试其实就是生产环境下面的一个测试,在线测试是面临着三个挑战
- 我们如何知道开发人员自测或者测试环境中没有问题的服务将在生产环境中工作?
- 我们可以从生产中收集哪些信息,帮助我们发布更高质量的产品?
- 我们如何检测和应对软件升级后发现的问题?
- 在线测试其实就是生产环境下面的一个测试,在线测试是面临着三个挑战
- 在线测试基于上面的三个挑战,要利用生产环境真实数据回流到研发环境提高产品质量,成为当前服务/微服务研发必需的测试活动
什么是在线测试?
- 在线测试是指在生产环境中开展的,或者利用生产环境数据开展的各种类型的测试活动
- 在做在线测试活动过程中要能回答以下几个疑问
- 如何构造生产环境数据进行测试?
- 灰度发布应该观察多久时间?需要观察哪些数据?
- 如何模拟现网用户真实使用场景测试?
- 现网架构越来越复杂,如何保证系统时时刻刻都是可用的?
在线测试包含的测试活动
- 导流测试
- 将现网数据引流到研发区进行测试
- 效果/目标:研发侧全量自动化测试通过后的 DailyBuild 版本,用现网真实流量进行回归测试验证,以确保测试版本对历史功能100%兼容
- 灰度测试
- 在灰度发布环节,将灰度用户作为测试数据进行预发布的验证
- 效果/目标:对于分布式系统版本灰度部署过程,比监控系统更精准校验版本正确性。辅助用户合理规划灰度流量及灰度时间,提升灰度发布效率
- 部署测试
- 正式发布前进行一轮冒烟测试,快速验证现网环境下是否正常
- 正式版本在部署后,需要通过 SmokeTest 快速验证新的版本在生产环境可用
- 在线持续测试
- 在生产环境中持续不断的对现网功能进行拨测
- 正式版本在生产环境运行时,模拟全球用户发起真实请求能力,以短、平、快的方式验证生产环境实时健康度
在线测试 —— 导流测试
- 基本原理
- 将真实的数据引流到研发区验证环境,将对比研发区鉴定结果
与生产环境真实结果是否一致,判断新版本是否有潜在的问题
- 将真实的数据引流到研发区验证环境,将对比研发区鉴定结果
- 从下图中得知,把生产环境的数据返回到研发区来,然后进行数据和流量的回放,通过日志里面进行结果对比
- 测试要点
- 请求收集:收集生产环境用户真实请求
- 数据同步:生产环境冷备 DB 数据,同步至 A/B 两套环境
- 流量回放:将真实流量回放至 A/B 两套环境
- 结果对比:比对 A/B 两套环境流量执行结果
在线测试 —— 部署测试
- 基本原理
- 部署在生产环境后,快速启动基于现网真实数据对该发布版本进行快速验证,保证新版本重要功能运行正常
- 测试要点
- 测试时机:在生产环境部署和快速启动部署测试
- 测试数据:基于生产环境的真实数据请求
- 测试范围:执行核心功能和常用功能对应的测试用例
- 测试结果:核心功能和常用功能用例执行,失败后立即定位,解决或者回退版本
在线测试 —— 在线持续测试
- 基本原理
- 产品发布之后,在生产环境下对产/品服务重要功能进行 7*24 小时持续拨测,以尽早的或者先于用户发现问题并协助研发人员快速修复上线
- 测试优点
- 一旦上线的服务发现问题,是通过自动化的脚本,实时的拨测,及时发现问题,而不是说从用户那儿得到反馈(当前什么服务宕机了),或者是派测试人员去手工去测试。因为有时候现网问题,可能跟环境,包括部署的方式,包括某一些服务器异常,都可能会影响最后的结果
- 测试要点
- 筛选用例:筛选版本重要功能对应的测试用例
- 定时拨测:定时(每隔5分钟、1小时)对重要功能进行拨测
- 现网告警:拨测用例执行失败并发送告警短信,提示告警等级
- 处理上线:研发人员根据告警快速处理并快速修复上线
测试度量指标体系和质量评估
测试度量指标体系
- 过程质量:衡量测试覆盖度、完备度和执行效率
- 结果质量:从功能、性能、安全和可靠性多角度衡量软件质量
测试推出与质量评价
- 测试退出条件
- 当达到了必要的信心级别,风险可以接受时
- 当发现缺陷的代价 > 缺陷发生引起的代价时
- 当达到测试完成标准(退出 / 成功标准)
测试能力成熟度评估
- 初始级
- 测试混乱,缺乏成熟的测试目标,测试可有可无
- 测试和调试不能分开
- 编码后才开始测试
- 测试目的表明程序没有错
- 缺乏相应的测试资源
- 定义级
- 测试的目标是验证软件符合需求,会采用基本测试技术和方法
- 测试是有计划的活动
- 测试和调试分开
- 编码后才开始测试
- 集成级
- 测试贯穿整个软件的生命周期,建立在满足用户或客户的需求上
- 有独立测试部门
- 根据需求写用例
- 有必要的测试工具
- 管理和测量级
- 测试时有度量和质量的控制过程
- 采用 IT 系统管理测试用例和相关文档
- 有缺陷管理系统(缺陷自定义级别)
- 没有缺陷预防机制
- 缺乏对测试过程中产生的数据的收集和分析
- 优化级
- 具有缺陷预防和质量控制能力;建立起测试规范和流程,并不断改
进测试 - 有缺陷预防机制(严格进行代码走查、审查、评审)
- 对于测试工具的使用有既定的流程
- 自动化程度高(性能和功能)
- 有缺陷分析机制(分析缺陷产生的原因,进而改善开发过程)
- 具有缺陷预防和质量控制能力;建立起测试规范和流程,并不断改
思考题
持续测试与传统测试的区别?为什么我们要在微服务测试过程中采用持续测试的方式?
从测试方法来说,有哪些测试方法,分别针对的场景是什么?
测试质量退出的标准是什么?
理想情况下测试范围应该足够广,频率应该足够高,但这只是理想情况。项目执行中
实际情况往往是因为赶进度,测试周期被压缩,同时测试人力也不足,这就要求测试
人员技能必须提升,以当时同时通过高度的自动化、测试、左移等方法,尽早的发现
问题,要做到这些就要开展敏捷测试测试方法
- 黑箱测试(black-box testing),是软件测试方法,测试应用程序的功能,而不是其内部结构或运作。此测试方法可适合大部分的软件测试,例如集成测试(integration testing)以及系统测试(system testing)
- 白箱测试(white-box testing,又称透明盒测试 glass box testing、结构测试 structural testing 等)是一个测试软件的方法,测试应用程序的内部结构或运作,而不是测试应用程序的功能(即黑盒测试)。可以应用于单元测试(unit testing)、集成测试(integration testing)和系统的软件测试流程,可测试在集成过程中每一单元之间的路径,或者主系统跟子系统中的测试
- 功能测试是按照软件的各个功能划分,进行有条理的测试。在功能测试时要保证测试项覆盖了所有的功能,以及各种条件的组合
最后,欢迎大家关注我的个人微信公众号 『小小猿若尘』,获取更多IT技术、干货知识、热点资讯。同时,我在公众号中分享了精心整理的一些视频资料(包括 Python全栈教程、AI教程、前端、数据库等),大家回复相应关键词即可获取网盘视频链接,感谢大家的关注😊
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)