一. 软件质量保障流程
1.1 微服务产品的特点
微服务架构下,一个大型复杂软件系统不再是一个单体,而是一系列相互独立的微服务,特点鲜明:
- 每个服务独立,开发技术栈独立
- 每个服务可以独立开发、部署、发布
- 服务之间通过轻量级通信机制沟通,常用的是 RESTful API
Micro Services
1.2 微服务产品测试的痛点
由于每个服务都有对外暴露的接口,而且服务之间还可能互相依赖,直接导致:
- 接口数量翻倍增长
- 测试场景翻倍增长
这使得在敏捷交付的模式下,测试工作挑战巨大。如何能在「周」「天」甚至「小时」的发布周期下,进行高效的测试,是微服务架构产品的测试中常常思考的问题。
1.3 软件质量保障全流程
1.3.1 角色
在产品的发布周期中,所有角色的联系相当紧密。每个角色有自己不同的职责,但最终都是为产品质量负责。
- 产品经理 —— 管理需求和项目计划
- 研发 —— 项目任务开发工作
- 研发负责人 —— 研发团队管理及代码质量管控
- 测试 —— 软件质量保障
- 运维 —— 应用部署和运行管理
除了按照「需求->编码->测试→发布」常规的顺序交流外,不同角色之间也随时交流信息。
DevOps Team
1.3.2 DevOps
无论是外部需求,还是内部反馈,都会被一一记录,供下一轮迭代评审。每一次迭代之中包含着无数局部迭代,由大家一起评审需求变更和承诺交付。
DevOps Loop
1.3.3 落地全流程
整个产品质量保障全流程从需求开始,一直到交付上线,全流程如下:
需求评审 → 编码 → 单元测试 → 代码扫描 → 构建镜像 → 部署测试环境 → 接口自动化测试 → 端到端自动化测试 → 提测 → 手动测试 → 发布 → 上线
利用 Jenkins 对接 JIRA、Git、SonarQube、Registry 等各种工具实现 CI/CD,让工程师不再把时间和精力花费在构建、测试环境搭建和自动化测试执行这些重复性操作上。
Process
通过提交代码自动触发流水线,进行单元测试,然后通过 Sonar-Scan 进行静态代码扫描,达到要求后会构建容器镜像,构建完成会自动部署测试环境,并触发自动化测试,测试通过后即可打上标签进行正式提测,在此之前的阶段都是通过自动触发,工程师只要把主要精力均放在结果上,待测试验证符合要求后,镜像才会最终发布并上线。
二. 集成测试
2.1 接口
接口测试通常分三步走:
准备测试数据 → 对被测接口发起请求 → 验证返回结果
测试数据是一个非常重要的输入,在接口不变的情况下,利用大量的数据驱动测试,从而实现较高的覆盖率。
通常我们使用命令行工具 cURL 或者图形化界面工具 Postman 对接口发起请求,无论哪个工具,都需要对返回结果进行断言以判断是否符合预期。
验证返回结果不仅仅是验证返回的状态码,还要验证返回值,返回值的准确性则需要通过查询数据库等方法进行验证。
另外,我们通过 Swagger 来管理接口文档,以力求不同的开发人员发布统一标准的接口文档,供大家使用。
2.2 接口自动化
通常,接口是提前定义的,且不轻易变化,比较稳定,因此测试工程师可以根据定义好的接口文档,在开发编码的同时,实现接口自动化测试脚本,提高未来的测试效率,并且可以实现测试前置。
我们基于 Pytest 框架以及 Swagger 3.0 标准封装改造出一款轻量级接口自动化测试框架,自动解析接口文档并且生成能被 Pytest 驱动的测试用例结构,工程师只花精力编写测试数据。
Mini API Test Framework
接口自动化的实现本不难,主要难在测试数据的准备和返回值的验证。
每次都使用相同的测试数据一定是不合适的,因此,测试数据需要有一定的自动生成能力。
而返回值有很多是测试过程中才能生成得知的,如 UUID ,这类数据的验证需要实时去数据库获取。
2.3 端到端
模拟用户场景,进行基于消费者契约的业务主流程端到端测试,覆盖用户触发频率最高的操作。比如以电商举例:
登录 → 搜索产品 → 选择 → 加入购物车 → 提交订单 → 确认支付 → 收货确认 → 添加评论 → 搜索订单
这种测试通常可以在时间有限的情况作为最基础的验证,以确保没有阻塞性问题,保证用户体验。
但一个产品的业务主流程通常不会发生太大变化,是一项不断重复的工作,因此,我们优化了测试操作流程,从而实施自动化。
2.4 UI 自动化
无论是 PC 端 Web UI 还是移动端应用 UI,现在都有比较成熟的自动化测试解决方案。对于 Web UI,我们期望其能够在容器中执行,所以选择了基于 Python 的 Selenium 调用 Headless Chrome「无头浏览器」,采用以关键字驱动的 Robot Framework 框架实现自动化测试。
WebUI 的操作主要是在页面输入和点击,因此我们采用 PageObject 设计模式封装页面元素,以此达到灵活使用关键字的拼装实现产品业务页面操作。
RobotFramework 伪代码
当页面出现错误,或非预期结果时,除了打印详尽的日志,还会自动截图插入到 HTML 的测试报告中。
三. 测试环境管理
3.1 构建镜像
我们所有的微服务均由流水线通过 Docker 构建出容器镜像,推送到独立的镜像仓库中。
Harbor
3.2 测试环境搭建
为了减少测试过程中脏数据的干扰,有些服务器是需要全新安装的。
除此之外,通常产品都是支持多种平台的,因此也需要在多平台上进行安装测试,并且需要按照交付文档中的安装方法进行验证。
3.3 测试环境自动化运维
考虑到迭代周期短,应用场景复杂,准备全套测试环境还是需要花费不少精力,所以我们采用自动化的方式来管理和部署测试环境,并且 VM 和 Docker 容器并存。
对于相对稳定的测试用第三方服务器,直接使用 VM 搭建,不需要特别的维护;一些用于产品的中间件或需要常常清理的测试用服务器,除了使用 ESXi Server 的 VM 快照回滚,还会结合容器化部署,测完即删。
这些操作都通过自动化脚本执行,并且由流水线根据需求自动触发。
四. 持续集成
4.1 单元测试
单元测试是产品质量检验的第一道关卡,其重要性和高效性不言而喻。单元测试做得好,会大大降低返工成本。单元测试除了关注通过率,还会在执行后通过 Sonar 分析出覆盖率,两者结合综合参考。
4.2 静态代码扫描
我们利用 Sonar-Scan 对所有代码进行扫描,并在 SonarQube 上设定一定的质量门限,达到质量标准的才会被标记为「通过」返回到流水线状态。
SonarQube
4.3 构建
微服务产品的各个组件都是以容器镜像的形式构建发布,推送到指定镜像仓库。我们直接在流水线中进行 Docker 构建并推送。
4.4 部署
检测到有指定版本新镜像生成,就会开始自动部署测试环境,并以无人值守的方式进行预测试。
4.5 自动化集成测试
通常我们把自动化测试前置到提测前,以此作为是否达到提测要求的快速验证。
测试通过后,会邮件通知到相关人员,正式作为 RC「发布候选版本」提测。
五. 测试用例管理
5.1 JIRA Zephyr
我们使用 JIRA 的 Zephyr 插件管理测试用例,若干测试用例通过模块和标签进行筛选分类。
通过 Zephyr 的测试循环来做测试计划,每轮发布中包含若干循环,一次循环相当于一次迭代。
每次迭代会关联具体的测试用例集,新功能和回归通过不同目录分类。
Zephyr 可以追踪出已分配用例的执行情况。
5.2 测试用例的分类
我们把测试用例按照功能模块进行分类,由于测试用例在 JIRA 中没有目录结构,因此需要靠标签来筛选。
另外,针对不同类型的测试用例,我们也做了特殊的标签,如 API、E2E 等等。
5.3 测试计划
Zephyr 在每一轮发布中可以包含多个测试循环,一次循环相当于一次迭代。
在每个迭代中,我们关联了计划执行的测试用例,并根据分类归在不同的目录中。
5.4 测试用例的执行状态
测试循环可以实时获取测试用例执行情况,若测试用例执行状态为「失败」,我们会关联一个 JIRA Issue。
JIRA Zephyr
另外,为了让所有人都看到直观的看到测试用例的执行与状态,我们利用 Grafana 定制了一个看板,使得测试结果可视化,让大家对产品质量有一个感性的解读。
5.5 测试报告
一份完整的测试报告,包含:
摘要总结
一句话总结本轮迭代测试的结论 代码改动范围 新功能 缺陷修复 测试版本 镜像名 镜像版本 测试环境信息 服务器名称 服务器版本缺陷验证 新发现 已修复 已验证测试详情 新功能验证 回归测试 性能测试 安全性测试
六. 缺陷管理
6.1 JIRA
缺陷的管理都在 JIRA 中完成,对于缺陷的发布,我们有着严谨的格式。除了填入 Sprint 信息供相关人员追踪外,还额外要求填入一些必要的标签,以标注缺陷发现的迭代周期、缺陷的类型、缺陷的功能模块,作为经验教训总结时的数据分析。
我们要求的必填项
项目
问题
类型
主题
模块
描述
Sprint
优先级
标签
6.2 缺陷的处理
开发工程师领取到属于自己的缺陷后,将其拖入「处理中」,修复自测后再拖入「待验证」交由测试工程师做最后的验证,并留下关于该缺陷的备注,如根本原因、解决方案等。
测试工程师验证时会填写详细的验证环境和步骤,有利于若问题重现,可找到历史记录进行分析。
6.3 缺陷的追踪
利用 JIRA 的冲刺看板追踪每个缺陷的当前阶段,在测试交付前应该都在「已验证后关闭」的状态,非问题的 ISSUE 一般不会很多。
JIRA Rapid Board
七. 发布后管理
7.1 缺陷分析
除了利用 JIRA 自身的看板,我们还利用 Grafana 增强了在当前冲刺期内的多样趋势图,以便于所有人都对一个周期内的进度有个直观感知,并且针对每个新功能也展现缺陷状态,这些数据都将作为本轮迭代软件质量的评估数据源之一。
Quality Status
对于缺陷的追踪,我们更关注在产品发布后,如何利用这些历史数据来提升未来的软件质量。
每轮迭代有一些正常规律,比如缺陷数量通常在前两个发布候选版本较多,相对复杂的新功能产生的缺陷数量会相对较多。
若出现后期某个候选版本缺陷数量突然增多,则要考虑产生该现象的原因,在发布前,就要考虑重新评估该原因带来的影响。
而对于没有产生任何缺陷记录的代码改动,同样要引起注意,需要评估测试的覆盖程度和深度。
所有缺陷的来源通常有:
- 测试发现
- 开发发现
- 客户现场
每种来源都将作为软件质量不同的改进方向。
而对于缺陷的类别,比如:回归、新功能、偶发、概率等等。
也是我们分析的一个方向。
其中回归问题是我们特别关注的,同时也是最影响软件质量信心的一种。
7.2 回归改进
每轮发布之后,需要对回归测试的范围进行更新,以增加新的覆盖点,主要的来源有:
- 最近一轮期间新功能的验证
- 最近一轮期间 Hotfix 的验证
- 最近一轮期间客户反馈的问题
- 最近一轮期间开发和测试新发现的缺陷
- 由于对技术和产品的积累,测试主动新增的测试用例
7.3 测试用例自动化
回归测试是一个非常尴尬的测试范围。
理论上来说,回归测试不应该出现执行失败,所以很多时候,回归测试是增强软件质量信心的一种手段。
但回归测试的范围是不断扩大的,每一轮的新功能测试范围,必然会有一部分会归纳到下一轮的回归测试范围内。
因此,回归测试的范围就像一个永远滚不完的雪球,越来越大,越来越重。
接口测试是回归范围中最容易实现自动化,并且投入产出效果最佳的测试范围,并且实现接口测试自动化的最佳时期就是开发过程中。
但仍然还有相当多的测试用例是需要多花点精力才能实现自动化的,因此在产品发布后,我们都会对这些遗留的可自动化测试用例持续的实现。
八. 结束语
软件质量是产品的血液,需要整个团队共同保障,特别是在 DevOps 团队中,成员的职责逐渐变得模糊,更应人人关注。
以上是一个比较通用的全流程,具体细节需要根据自身产品特性做调整。