- 背景介绍
- DevOps 流程 - 需求、开发、测试、运维、监控一体化
- 敏捷开发与 DevOps - 开发和测试、运维应该如何协作
- 为什么要自动化测试?
- 介绍 CI/CD 流水线
- 如何设计测试流水线
- 实战经验:优化流水线
- 实战经验:优化测试框架
背景介绍
为了提高软件的研发效率、保证软件质量、高效服务运维,溪塔团队在开发管理上实践敏捷开发、使用 DevOps 进行自动化运维、实行持续的自动化测试。在介绍怎么做之前,先说下溪塔团队做了什么,这样能比较好理解知道团队为什么要这样做。
溪塔科技团队在 2016 年开发了一款区块链软件 CITA,并在 2017 年进行了项目开源: https://github.com/cryptape/cita
CITA 是溪塔团队 从头开始自主研发 的一个高性能区块链内核,具有微服架构、水平扩展、组件可插拔、高性能这些特质。
区块链服务简单可以看作是一种分布式的账本同步系统。为了简化应用开发者的使用,溪塔团队开发了与之配套的各种开发、调试工具、组件,例如:
CITA 内核与各组件的关系图:
这些工具都是开源的:
https://www.citahub.com/#componentArea
具体怎么做
溪塔团队使用敏捷开发中的 Scrum 框架管理团队目标和进度。敏捷开发的目标是通过迭代开发的方式交付可工作的软件。溪塔团队会将一个大的版本作为一个Milestone(里程碑),定义好必须要完成的总目标和时间点,然后切分成几个较短工作周期的 Sprint(迭代),每个 Sprint 有自己要完成的阶段目标。
溪塔团队使用 Story Point 来评估每个任务的完成时间,使用燃尽图反馈任务完成进度,以便可调控每个 Sprint 的节奏和进度,如下图,是溪塔团队一个子产品开发过程的各个 Sprint 里的燃尽图:
在具体的任务管理上溪塔团队使用 Kanban(看板)工具来跟踪每个成员的任务状态,如下图:
看板是一种图形化的展示工具,由于人类天生对视觉化的信息更容易理解,通过它可以很直观的反应每个任务的状态、同时也是一种工作量的直观呈现,让开发组中每个成员都可以清晰知道自己、同时了解到其他人的工作进展。
实践 DevOps
软件开发不只是把代码编写出来就完事,还需要经过测试保证完整性、把测试后的软件部署到服务器上,还要设置监控保障服务运行正常,并能收集反馈给产品、开发团队对软件功能、质量进行持续的改善,才是一个完整可用的服务开发到上线的过程,整个过程如上图所示,一环衔接一环。
如何实践 DevOps
如上图所示,DevOps 不单是运维团队的事情,而是开发、运维、测试各种岗位人员一体化实施的一个过程。溪塔团队要求做到流程规范化,这样各个职能成员能互相了解对方的工作输出预期,才能高效协作。流程规范化后,才能使用工具进行自动化来提高工作效率和减少人为产生的故障。让各环节的协作像是流水线般清晰可感知、可预期。
有人认为要实践 DevOps 要求团队成员都是全栈工程师,而溪塔团队认为专业分工才能深入和精通,因此可以将团队分为区块链开发、测试开发、运维开发团队,注意到每个岗位都是有“开发“字眼,具备有编程能力的团队才是能有效实践 DevOps 的根本。
给溪塔团队设定3个目标:
-
开发区块链软件 - 软件代码 用 CI 进行自动化代码质检、测试、构建、发布
-
测试区块链软件 - 测试代码 用 CI 进行冒烟、回归、性能、稳定性测试
-
运维区块链服务 - 监控服务 用 CI 进行主动监控、被动告警
对这样的团队的要求:
-
开发、测试、运维均要求有编程能力
-
开发、测试、监控服务的代码,均遵从相同的开发流程、使用CI工具
开发流程
使用 GitHub Flow 进行代码管理, 本地创建 feature 分支 -> 发PR -> 代码审查 / CI 检查 -> 合并 master 分支:
自动化运维
使用 CI/CD 流水线 进行自动化构建、测试、发布、部署:
开发人员的代码开发完成会进行代码审查、静态代码扫描检查代码规范和代码安全检查、运行自动化测试;根据不同的分支合并策略进行不同环节的自动化部署,如合并到 develop 分支会触发 staging 环境的部署,部署成功后自动通知测试人员进行验收测试;合并到 master 分支会触发 production 环境的部署,部署成功后自动发送上线通知让运营人员进行运营使用。使用自动化的 CI/CD 工具和流程,可以把功能开发到上线时间,缩短到开发人员提交代码的最后一刻,并且在 CI 服务上有记录,每个人都能知道是什么人、在什么时候、部署了什么改动、到哪个环节,提高了运维效率也减少了人工操作过程的人为事故可能性。
服务监控
运维使用 ELK 服务进行日志收集、数据分析,如下图,溪塔团队对测试链各个节点上服务的日志收集和分析,出现软件故障时方便运维、开发人员了解原因。
为了方便 CITA 服务的运维,溪塔的运维团队开发了 CITA 的监控服务,可用于监控节点中 CITA 的服务运行情况,包括采集区块链数据、CITA 进程的存活监控、运行环境监控、故障自动告警通知,提供给开发、运维人员友好的可视化的面板,如下图:
同样的,这个监控工具的本身的开发流程也是一样遵从同样的 DevOps 实践,同样也是开源的: https://github.com/cryptape/cita-monitor
持续自动化测试
提高了开发、运维效率,还要保障软件的质量,这个是溪塔测试团队的工作重点。下图是软件测试中著名的测试金字塔,测试金字塔说明了一种两难的境地:越是上层的测试,就会耗费越多的精力、时间和成本。
溪塔的测试团队的工作重点正是最耗时间、资源的系统测试的自动化。这并不是说开发团队就不用管测试了,开发团队主要编写单元测试、集成测试等的白盒测试。
因为溪塔团队认为:
-
自动化测试才能让 QA 的价值最大化;
-
自动化需要 CI 工具来做管理和执行。
区块链软件是一种多实例运行的系统,只保障了单元测试、集成测试的结果是远不足够保障系统最终是可用、结果是可信的,而区块链又是一个用计算机软件解决「信任」的工具,软件首先必须是可信的,产生的数据才能让人信任,因此溪塔团队对测试工作投入大量的精力来保障软件的质量。
溪塔团队做的系统测试是一种端对端级别的、在仿真环境中软件运行结果的黑盒测试,为了提高测试工作效率,我们使用了 CI 流水线来管理多种测试策略。
测试流水线
什么是 CI/CD 流水线(Pipeline)?
如下图所示,Jenkins 是溪塔团队使用的 CI 工具之一,一条 CI/CD Pipeline 像是一节节的管道,代码提交后会触发 CI 的运行策略,执行自动化的构建、测试从而实现持续集成或持续部署流程,不同管道环节有各自的输入、输出,任何一个环节出问题都阻塞影响到整个管道的工作。
进行 CI/CD 流水线设置之前,先思考 3 个问题:
-
如何设计一条合理的流水线?
-
如何设计测试流水线?
-
为什么要设置多条流水线?
流水线设计关键要素有 2 点:
-
设计合适的Workflow:工作流程,如:stage 1 -> stage 2 -> stage 3
-
设计Workflow 中的 Stage Job:阶段工作,如:unit-test, build, integration-test, code-audit, staging-deploy, production-deploy
每个 Stage Job 也有 5 个设计关键要素:
-
Up/Down stream:上下游的Stage Job
-
Trigger: 触发条件
-
Input/Output:输入参数;输出构件产物、输出参数
-
Steps:执行步骤
-
Notification:结果通知;最后的 stage 都要有明确的通知对象
众所周知做软件开发需要有 PRD(功能需求文档),同样的流水线设置也需要有设计文档。在设置具体的 CI/CD 流水线前,要做下流水线设计,如下图是溪塔团队其中 2 条流水线的设计文档:
设计好各种流水线的作用、执行策略和运行步骤细节后,就可以在 CI 工具上进行相应的设置,不要一边想一边改 CI 配置,特别是对于复杂的流水线应该设计好再做设置,这样一来流水线自己也有了文档留存,方便其他运维同事协作,开发和测试也能清楚工作流程。
如下图,是溪塔团队设置的发版测试流水线:
发版测试流水线分为 4 个阶段:
-
构建测试对象:获取软件代码,自动编译生成不同算法版本的二进制文件bin
-
生成测试运行环节:把 bin 文件放入可运行的环境,构建 Docker Image
-
运行测试用例:对不同 bin 版本运行自动化测试用例;并行执行节省时间
-
生成测试报告:自动汇总各个版本的测试结果,自动生成一份包含测试对象、测试环境、测试结果的报告;并自动把构建产物存档,方便对外发布
多种流水线策略
发版流水线无疑是溪塔团队日常开发中最重要的一种流水线,为了能让开发人员尽早发现代码质量问题,团队还设置各种策略的测试流水线,例如用于保障开发主分支的系统测试流水线、用于保障测试代码质量的冒烟、回顾测试流水线;用于保障软件性能的性能测试流水线等。
-
系统测试流水线:
-
当开发人员在开发的 develop 分支有合并时执行全量测试用例集的回归测试,用于保障开发主分支的代码质量。
-
冒烟测试流水线:
-
用于做测试用例的增量,用于保障测试代码的代码质量;当测试人员提交测试代码的 feature 分支时执行;只运行 P1 级别的测试用例集,执行速度快,加快代码审查、合并流程;复用由发版流水线生成的测试对象。
-
回归测试流水线:
-
用于保障测试代码的代码质量;当测试人员合并测试代码的 develop 分支时执行;运行全量的测试用例集,执行速度慢,但避免引入有破坏性的代码;同样是复用由发版流水线生成的测试对象。
其他测试流水线
-
性能测试流水线:
-
除了保障软件的可用性,溪塔团队非常关注软件的运行效率,因此团队设置了性能测试流水线。性能测试关注的结果是一些性能指标,如反映服务处理能力的 TPS、延迟和响应时间等。但性能测试的运行代价很高,需要独占主机资源并长时间运行。因此溪塔团队设置成每天晚上凌晨 2 点半自动运行性能测试流水线,运行完毕会生成图形化的报告发送邮件通知开发团队。这样开发团队每天都能了解到主分支的性能变化情况,当出现有重大性能变化时可以及早进行优化修复,而不是等到发版测试阶段才知道结果。
-
稳定性测试流水线:
-
溪塔团队还关注软件的稳定性,软件的稳定性是指在服务有大量请求压力时各种关键功能还能正常工作。因此溪塔团队设置了稳定性测试流水线,在发版阶段执行,可以按需要选择压测的参数。
-
可用性测试流水线:
-
开发人员做了一些重大改动,在合并到主分支前,想了解是否有其他副作用,因此运维提供了可用性测试流水线,开发自己选择需要测试的分支执行即可获得该分支回归测试的结果。
-
性能改进测试流水线:
-
开发人员做了一些性能相关的改动,想了解整体上的性能变化,因此运维提供了性能改进测试流水线,开发自己选择需要测试的分支执行即可获得该分支回归测试的结果。
在 DevOps 模式的协作重点
在 DevOps 模式下开发、测试、运维人员的协作重点为:
-
运维的工作目标是使用自动化运术为开发、测试提供便利流程、工具,减少重复工作
-
测试的工作目标是使用自动化运术提高测试效率、保障开发成果质量
-
开发享受自动化的便利,专心做开发,提高软件质量
没有自动化则没有效率提升和质量持续保障,而自动化工具的维护当然也是有代价的,这个正就是实践 DevOps 的团队真正要做的工作。
实战经验分享
如何优化流水线和测试框架,以下是我们实践的一些技巧和收获:
流水线优化技巧
-
流水线互相制约保障质量
-
系统测试流水线保障开发代码质量
-
回归测试流水线保障测试代码质量
-
-
配合 GitHub Flow 约定自动化触发规则
- feature 分支跑冒烟,冒烟过了合并到 develop
- 合并 develop 跑回归,回归过了合并到 master
-
重用测试对象
- 发版测试构建测试对象
- 冒烟、回归使用已构建的测试对象
- 测试对象放入Docker Image 做版本管理,本地测试和CI上使用相同测试对象
-
存档构建工件
-
合并测试报告
-
测试环境使用 Docker Container 隔离
-
每条测试用例隔离运行
测试框架优化技巧
-
使用环境变量及 Docker Image Tag 获取测试对象
-
使用 Docker Image 获得统一的测试环境
-
出错自动重试用例
-
测试用例并行执行
-
管理输出日志
-
输出直观的测试报告
什么样的测试报告才是好的报告?
测试工作的最终呈现结果就是测试报告,那什么样的测试报告才是好的报告?溪塔团队认为一份清晰准确的测试报告总结内容应该包含:
-
测试对象
-
软件名称
-
软件版本
-
源码地址
-
源码commit id
-
bin文件输出的版本信息
-
-
测试环境
- 测试代码的commit id
-
测试用例
-
测试结果
而一个好的测试框架应该能帮助测试人员自动生成这样一份测试报告,提高测试人员的工作效率和准确性。
以下就是溪塔团队使用的测试框架(使用 TestNG 作为基础框架)得到的报告:
溪塔团队对测试框架持续改良,使得自动生成测试报告中能输出我们关注的测试对象版本、测试环境、测试代码版本等信息,收到测试报告通知时,每个人都在通过报告可以清晰并准确知道测试的是什么、是什么结果、怎么测试的。
溪塔团队认为企业协作的高效秘诀之一是:Don’t ask, look by your self! (不用问,自己看)可以主动感知的信息才有效率,通过询问才能得知是低效的工作方式。
以上便是溪塔团队对区块链软件的工程质量控制的一些经验分享,请注意,每个企业都有各自的优势、短板或历史包袱,经验不能复制只能参考,适合自己的才是最好的,谢谢。