专栏文章 持续集成的开源方案攻略 (一) 概述

孙高飞 · February 11, 2020 · Last by 薄荷可乐 replied at February 12, 2020 · 998 hits

前言

前年的时候我们组的超哥曾经在MTSC大会上分享过我们做持续集成的经验, 我也曾经写过一个帖子介绍了我们大规模持续集成策略的内容:https://testerhome.com/topics/15058
但是之前我们讲了策略,但没有告诉大家我们具体的实现, 所以这一次我会展开更多的实现细节, 针对这些技术我会写一些教程出来帮助大家理解如何来实现。 同时我是一个开源技术选型的拥护者,在项目中能用开源技术就绝对不自己造轮子。所以这个系列的特点也是技术选型都是开源项目,有耐心肯努力的同学一定可以复制到自己的项目中来。

持续集成理念

其实我是一个理论知识匮乏的人,我到现在都没读完那本大名鼎鼎的《持续交付》, 当然这里我也不在这里跟大家说扯持续交付这个概念了, 因为对于我们这种TO B公司来说这是完全没有的事(3个月发一个版本,这还持续交付个蛋~~)。所以对于持续集成的理解,我只有自己实践出来的经验而已。

持续

先来说持续, 这两个字代表了不间断的对系统进行测试。 宗旨是研发同学每一次的代码提交都会经过相应的测试来验证。 做道尽早测试,尽早发现问题,尽早解决问题。 所以一般都会通过jenkins这种CI工具做触发式的pipeline。 比如在gitlab上定义好webhook,每当有push event或者merge request event的时候就会触发pipeline开始测试。 测试过程有单元测试也有集成测试。 这样我们可以就会对研发每一次提交的代码都有一定的信心, 如果提交的代码中有bug也能及早发现。

集成

集成两个字非常重要同时也容易被忽略。 经验证明我们非常多的bug是发生在部署阶段以及模块与模块之间的交互上,也就是可能我们每一个模块跑的UT可能都没有任何问题,但是一旦产品部署起来,模块之间开始交互的时候,bug就源源不断的出现了。尤其是在微服务架构下,几十上百的模块在系统中交互,那么集成测试的重要性就不言而喻了。 而在我们实践持续集成的时候也曾经针对集成测试发生过分歧。 众所周知UT运行速度很快,每当有代码提交时触发UT是没有任何争议的。 但是集成测试(比如接口测试) 的运行速度让人担忧,如果研发频繁提交代码的话运行效率是一个问题。 但是集成阶段非常重要,我们的最终决定通过增加并发执行策略以及只跑smoke级别的简单测试来解这个问题。 甚至我们建议即便不跑集成测试,也要把子系统部署起来验证是可以运行的。我们的经验是如果不做这些可能最终提测的时候模块连部署都部署不起来。 所以最终我们的策略是。

  • 每次提交代码触发pipeline运行UT, 集成部署 以及简单的smoke的集成测试
  • daily build 一个全量的测试环境, 运行全量自动化测试用例。

技术选型

首先从全局角度考虑,我们需要这样一个流程。

从单个模块考虑,持续集成的流程是 -- 研发push代码开始触发pipeline-> UT -> 打包,制作并推送镜像 -> 部署 -> 各种测试 -> 发送report。 我们来看这里面涉及到的技术选型。

Jenkins pipeline

现在的QA面对的是大量的业务模块(微服务的副作用),越来越长的持续集成流水线。 假设一个持续集成流水线平均要5个job来维护,就算只有10个模块那也有50个job。 大量job的维护成本越来越高,这些通过UI配置的job从流水线的可视化,配置的复用等方面都相当的差。 所以当你面对一个拥有几十上百个服务组成的大型系统,还用以前的方式组织持续集成的流水线是几乎不可能的。想象一下维护几百上千的jenkins job,而且由于配置复用做的很差,研发和部署稍微修改一下就要更新几十个job的恐怖场景吧。 所以选择jenkins 2.0 提供的pipeline 几乎是必然的。

上面是我们一个模块做的集成测试的pipeline。 在这个视图上点击pipeline中的每一个节点都能查看详细的运行状态和运行日志,可视化方便已经做的相当不错。 而pipeline as code的理念让我们把流水线的配置从UI上解放出来变成了用groovy脚本来配置的方式, 这个方式让我们可以一目了然的在一个脚本里看到整个pipeline的全貌。 并且jenkins提供全局共享库的方式让我们把公共的逻辑做成共享库分享给所有pipeline使用,种种设计解决了我们的维护噩梦。

docker && k8s

到了这个时代我很难想象维护一个上百个模块的系统的时候,不使用容器编排技术将会是多么痛苦的事情。 2年前我写《k8s 下的大规模持续集成与环境治理》的时候就提过,在一个大型系统中,持续集成最大的技术难题就是环境治理。 上百个模块每日不停的构建,集成,测试。 需要的是数十台机器的支持, 这里面资源的调度,环境的依赖,自动化为运维的要求等等都是非常恐怖的。 如果没有k8s这种容器编排框架来解决这些问题这个活简直没法干,那得需要铺多少人力来人肉维护。 在17年我们团队在测试环境中率先引用k8s的时候,我只用了一半的精力就维护了60~70套左右的环境。 当然当时产品还没有微服务架构, 所以总共部署的模块也就600个左右。 但半个人力维护这个数量级的测试环境,可见这套技术栈为我们提高了多少效率。


而抛开测试环境的治理, jenkins与k8s的集成也同样为我们带来了额外的收获。 相比于把jenkins master节点部署在k8s中,利用k8s的高可用能力的实践, 我其实更喜欢的是jenkins pipeline 对 k8s的支持。 我们可以在jenkins pipeline中使用非常简单的指令就可以让jenkins 动态的调用k8s接口创建pod并作为jenkins的slave 运行流水线的能力。 这解决了我们对于负载均衡的痛点。 当有大量的构建任务的时候,你会发现单台机器的性能已经跟不上了, 再引入k8s之前,我们总会在编辑上遇到单台机器的性能瓶颈--大量的编译job 打满了CPU,构建效率变的很差。 所以我们一定希望架构是可以横向扩展的,通过加机器来解决性能问题。 而jenkins与k8s集成后, 很好的解决了我们这个问题。

测试框架

在我们团队里,其实不要求测试框架的统一的, 甚至连使用的语言也没有硬性的要求的。 大家都是喜欢用java就用java,喜欢用python就用python。 但是我们的report格式却是高度统一, 不管是用java的还是用python的,使用的都是allure框架来生成report。 这样方便在pipeline中集成所有测试类型的测试报告。 比如一开始的pipeline的那个图里,我们是并发的执行了sdk的测试和UI自动化测试的。 SDK是python语言的sdk所以必须使用python进行测试,而UI自动化选择的是java技术栈。 正因为这两个自动化测试项目使用的都是allure 框架来生成report。 在pipeline中,整个所有测试类型的report到一个视图中是比较重要的。 所以在这样的前提下,我们选择的测试框架是。 java: testng+allure(UI自动化为selendie,API自动化为rest-assured)。 python:pytest + allure

其他工具链

辅助测试的工具很多,这里列举几个常用的。

  • jacoco:实时代码覆盖率, 被测服务在启动时使用jacoco的agent启动,可以在服务启动后实时统计覆盖率。 之后就可以统计API,SDK和UI自动化的覆盖率了。
  • mock-server: 开源的mock-server, 它的作用应该不用多说。
  • jvm-sandbox:刚集成进来不久的java字节码注入工具,用来在测试中通过注入测试代码来模拟一些异常场景和系统临界点(比如触发熔断)。 增加覆盖率。

以上都是开源项目, 使用起来并不难。 但是在pipeline中自动化的使用它们是一个难点, 尤其是在容器化环境中。

结尾

开篇概述就讲这么多吧, 我不是一个特别能说概念的人, 所以接下来的文章会围绕着上面说的这些技术的使用展开~

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 4 条回复 时间 点赞

坐等更新

请问题主,再上面持续中,提到了,既有单元测试,也有集成测试。想问下,集成测试如何做的呢,尤其针对于新的功能的提测,如何做到的集成测试

lukezc90 回复

持续集成测试的都是老的功能, 新的功能只有提测后才能添加对应的自动化测试用例

孙高飞 回复

测试左移,提前介入编写自动化测试用例

需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up