写点什么

一次软件的可靠性测试实践

  • 2022 年 5 月 30 日
  • 本文字数:2807 字

    阅读完需:约 9 分钟

一次软件的可靠性测试实践

本文由 Pingcode 孙敬云分享

前言

可靠性测试是一种非功能测试,它可以发现那些隐藏在软件内,会导致软件能力下降的缺陷。在修复这些缺陷之后,我们可以让目标软件在长时间运行的状态下,依然可以处理等量的数据。


因此为了保障公司内各个项目的可靠性水平,我们便引入了可靠性测试。


我们对第一阶段的可靠性测试定义了这样一个目标:在特定的环境和较长的时间范围内测试一下"X"的维持能力。我们要重点关注的是"X 是否足够稳定(业务处理能力的波动值)”、“X 是否存在内存泄露问题"、"X 的索引效果是否明显"等。


本文大致分为三部分:


  • 方案概述

  • 主程序

  • 报告分析


方案概述

基于我们要达成的目标,具体的落地方案是这样的:

`Conainer: *`是我们本轮测试中涉及到的所有服务实例,其中`X-Service1`,`X-Service2`和`X-Service3`是目标系统 X 的三个核心模块,我们需要单独运行它们。

这里需要特殊说明的是:首先,可靠性测试方案是基于我们的「 集成测试方案 」实现的;其次,测试什么样的场景和测试过程本身是分开的。因此对于「可靠性测试方案」的核心功能来说,它既不需要关心如何构建测试环境,也不需要关心具体要执行什么样的测试用例,它的核心就是要监测我们在重复模拟客户使用场景的过程中,各个相关服务实例的实际状态。

集成测试方案:「 跨团队项目的集成测试实践分享 

我们将上述核心拆分为四个部分:用例执行器、状态管理器、报告生成器和通知模块。

1.用例执行器

用例执行器的定位很简单,就是重复的执行指定的”测试用例“。在每次执行”测试用例“时,用例执行器都会对外推送相关事件,这里最重要的就是”完成“事件。

订阅者可以在”完成“事件中获悉单次执行的结果,比如执行了多少,失败了多少等等。

2.状态管理器

顾名思义,状态管理器管理着所有服务的状态,通过它可以方便的获取到每个服务的最新状态。当然它也记录着用例执行器推送的数据,例如用例执行总数、失败总数、最近一个周期用例执行数和最近一个周期失败数等描述业务能力的数据。

3.报告生成器

报告生成器的职责有两个:一是定义报告的数据格式;二是生成对应格式的报告。生成报告所需的数据基本上都能在状态管理器中拿到,如果我们需要展示更多的数据,这就需要对状态管理器进行扩展或者引入更多的”插件“;同样的如果需要更多样的展示,也可以对报告生成器进行扩展,默认生成的报告是这样样子的:

”列“里定义了所有相关服务实例的 CPU、Memory、Network 和 Disk 信息,”行“里则每隔一段时间就采集一次相关的数据。

4.通知模块

通知模块也有两个职责,立即通知和定时通知。但是通常情况下,我们只会用到定时通知,比如每隔 10 分钟向指定地址发送一次最新的报告。

主程序

有了这四部分,可靠性测试的核心也就完成了。我们再为它们包装一个”主程序“,”主程序“的职责是将这四部分串联在一起,这样使用起来就更容易一些,比如将入口定义为这样:

 await DurabilityPlatform.run(projectName, { "mongodb": MongoDBDockerExecutor, "redis": RedisDockerExecutor, "elasticsearch": ElasticsearchDockerExecutor, "service-Y": ServiceYDockerExecutor, "service-X1": ServiceX1DockerExecutor, "service-X2": ServiceX2DockerExecutor, "service-X3": ServiceX3DockerExecutor }, { duration: 1 * 3600 * 24 * 1000, // 持续测试1天 interval: 10 * 60 * 1000, // 每10分钟采集一次最新状态 incomingWebhook: "https://hook.worktile.com/incoming/xxxxx", // 定时通知的地址 specsPath: path.join(__dirname, "specs"), // 测试用例所在的文件夹 onStart: async () => {  // 向PingCode中创建一个测试计划        }, onEnd: async (reportURL: string) => { // 更新PingCode测试计划的状态        }    });
复制代码

技术方案确定之后,下一步就是回归目标本身:在特定的环境和较长的时间范围内测试一下"X"的维持能力。我们需要确定一些用户的使用场景,然后通过测试用例的方式模拟这些场景。

例如用户可以在”X“系统中创建资源、更新资源和获取资源。那么我们就把这个过程模拟出来。在用例执行器指定的用例文件夹下创建一个新的测试文件:
describe("Simulate user scenarios: Create, Edit and Get", () => { it("Create a resource;expect-ok", async () => {}); it("Edit a resource;expect-ok", async () => {}); it("Get a resource;expect-ok", async () => {});});
复制代码

可靠性测试框架会反复的运行这几个测试用例。随着时间的推移,同样的几个测试用例,它的运行效率可能会下降,我们就是要通过场景的模拟来观察到数据的变化。

比如我们运行了一段时间之后,可以观察一下业务吞吐的趋势,是保持住还是持续下降?是缓降还是指数降?有没有突然的断崖式下降?

总之,写的测试用例一定要覆盖主要的业务点,这样才能更全面的发现问题。

报告解析

在可靠性测试中,写框架、写测试是一部分,数据的解析是另一部分。比如我们看下面一部分数据:

从上图可知,在同样的时间周期内,同一份用例的执行效率在随时间下降。我们将它转化为报表:

这说明 X 系统的业务吞吐能力会随着时间的推移逐渐下降,而且在运行很少的时间后就会出现这个问题。那我们需要再深入研究一下:

我们发现 Service-Y 的 CPU 一直处于高位,内存也有缓慢上涨的趋势,这会是根本原因吗?我们还需要再深入研究……导致 Service-Y 表现异常的原因是什么并不重要,重要的是:报告解析的过程,就是一个观察数据->大胆猜想->更多数据->猜想验证的过程,它需要经验支撑,但是也离不开数据的支持。

结尾

我们需要知道,可靠性测试中的数据指标并不是固定的,在本文中选取了"实际运行用例数"、”实际失败用例数“、”每 10 分钟运行用例数“、”每 10 分钟失败用例数“、”各个服务 CPU 使用率“、”各个服务内存使用量“、”各个服务硬盘使用量“和”各个服务 IO 使用量“,只是为了达到我们定义的目标。对于更多的场景,我们需要根据实际情况再采集相关数据,本文旨在分享经验,而不是在定义什么。

非功能测试的本质还是要通过适当的客观数据来反映服务的状态,这需要我们有不断改进的态度,而不是一劳永逸的设想。好了,本期内容就是这些。


最后,推荐我们的智能化研发管理工具 PingCode 给大家。

PingCode官网

关于 PingCode

PingCode 是由国内老牌 SaaS 厂商 Worktile 打造的智能化研发管理工具,围绕企业研发管理需求推出了 Agile(敏捷开发)、Testhub(测试管理)、Wiki(知识库)、Plan(项目集)、Goals(目标管理)、Flow(自动化管理)、Access (目录管理)七大子产品以及应用市场,实现了对项目、任务、需求、缺陷、迭代规划、测试、目标管理等研发管理全流程的覆盖以及代码托管工具、CI/CD 流水线、自动化测试等众多主流开发工具的打通。


自正式发布以来,以酷狗音乐、商汤科技、电银信息、51 社保、万国数据、金鹰卡通、用友、国汽智控、智齿客服、易快报等知名企业为代表,已经有超过 13 个行业的众多企业选择 PingCode 落地研发管理。

用户头像

还未添加个人签名 2021.02.01 加入

还未添加个人简介

评论

发布
暂无评论
一次软件的可靠性测试实践_软件测试_PingCode研发中心_InfoQ写作社区