Docker引领测试革新

ChelseyInou 8年前
   <p>随着Docker技术被越来越多的人所认可,其应用的范围也越来越广泛。本文将从测试类型、Devops、自动化测试、测试场景、测试实践等方面介绍Docker对软件测试技术的影响。我假设读者在看这篇文章时已经对Docker和其所依赖的核心技术有了一定的了解。如</p>    <h2>1.传统软件开发流程的痛点</h2>    <p>在传统软件开发流程中,开发团队在完成功能代码编写后,会首先进行自测,之后将代码提交到Git仓库中。在每一次迭代转测试时,开发团队会首先构建转测试的二进制文件,之后由测试团队对版本进行验证,验证通过后会将版本提交给运维团队。之后再由运维团队将产品发布件部署到运维服务器中以提供给客户使用。</p>    <p>在这个流程中会有如下痛点:</p>    <p>(1)开发、测试和运维环境不统一。</p>    <p>这导致了有些本该在开发阶段发现的软件缺陷可能会遗漏到测试或运维阶段才能发现。有时发布件在开发环境中运行的很稳定,而在运维环境中刚刚运行就挂掉了。这时运维团队不得不找开发团队来救火,导致了整个团队工作效率下降。</p>    <p>(2)无法准确获取客户的软件环境。</p>    <p>我们往往不能直接复现客户报的软件缺陷,不得不去客户现场进行调试,滞后了解决问题的时间。</p>    <p>(3)开发者在提交代码前往往未做充分的测试。</p>    <p>开发自验工作取决于开发者的责任心,而没有一种机制来保证自验工作的进行。导致了很多低级的软件缺陷遗漏到测试和运维团队。</p>    <p>(4)开发团队无法复现测试团队报出的软件缺陷,导致两个团队出现相互推诿的现象。</p>    <p>(5)配置测试环境的时间较长,测试自动化成本高。</p>    <p>传统环境往往使用虚拟机,而其消耗资源高、部署速度慢,导致自动化的效率不高。</p>    <h2>2.当前测试技术面临的挑战</h2>    <p>主要的挑战如下所示:</p>    <p>(1)配置一致的测试环境。</p>    <p>(2)快速部署软件。</p>    <p>(3)并行执行测试,在并行的同时还需确保测试任务各自的环境不被污染。</p>    <p>(4)成功的复现软件缺陷。</p>    <p>(5)创建清洁的测试环境。</p>    <p>(6)正确配置测试工具。同一个工具需要适配到不同的linux发行版中。</p>    <p>(7)快速部署多个测试主机。</p>    <p>(8)快速导入测试数据。</p>    <p>(9)快速清理测试环境。</p>    <p>(10)快速保留、复制、恢复测试环境。</p>    <h2>3.Docker对测试技术的革命性影响</h2>    <p>(1)更早的发现单元测试中的软件缺陷。</p>    <p>测试驱动开发是软件工程中一个具有里程碑意义的创新,即开发者在提交开发代码的同时也要提供对应的测试代码,在代码提交后系统会自动进行一轮自动化测试。通过Docker可以快速部署测试环境,可以有力的支撑自动化测试,从而确保在第一时间发现单元测试中的软件缺陷。</p>    <p>(2)为功能测试和集成测试提供清洁的测试环境。</p>    <p>很多公司由于成本问题,不得不在一个虚拟机中运行不同类型的测试任务。而这些任务在运行时往往会导致环境污染。通过Docker技术的隔离性,可以有效地解决测试环境的污染问题。</p>    <p>(3)让测试团队和客户丢掉冗长的配置文档。</p>    <p>开发转测试时往往带有较长的环境部署文档,而在这些文档中往往存在部署过程跳步的问题,测试团队很难一次准确的将环境部署成功。而现在可以通过Docker镜像将配置环境的过程简化,测试团队省去了查阅文档的过程,只需要基于开发团队提供的Docker镜像就可以轻松的配置测试环境。</p>    <p>(4)便于复现客户报告的软件缺陷。</p>    <p>当客户使用软件发现缺陷时,可以将其所使用的环境打包成镜像提供给开发团队。开发团队通过镜像即可获取与客户一致的软件环境。</p>    <p>(5)通过Dockerfile可以梳理好测试镜像制作的流程。</p>    <p>如果流程步骤需要微调时(如将安装gcc3.4改为安装gcc4.3),可以将Dockerfile中对应的信息进行修改并重新创建新的镜像,不必手动重新配置运行环境。</p>    <p>(6)可以将成熟的测试套或测试工具通过镜像共享。</p>    <p>这样可以支持软件在不同linux发行版中成功的运行,软件提供商可以将主要精力放在完善功能上,不必投入过多时间将软件适配到不同的linux发行版中。</p>    <p>(7)利用Docker生态中的工具可以快速创建可伸缩的测试环境,大大减少了测试所消耗的时间。</p>    <p>可以在短时间内快速集中资源来完成一项测试任务,在任务完成后又可以快速的对资源 进行回收,有利于提升资源使用效率。</p>    <p>(8)优越的性能指标。</p>    <p>通过优于虚拟机的性能,Docker可以提升测试效率。通过“-v”选项可以将主机的目录快速映射到容器中,可以实现测试文件的快速共享。通过“--rm”选项可以在测试完成后第一时间删除容器,以便释放系统资源。</p>    <p>(9)轻松的恢复测试环境(包括内存)-CRIU技术 Checkpoint Restore In Userspace</p>    <p>结合CRIU技术,可以实现容器运行状态的保存,这项技术也是容器热迁移的基础。</p>    <h2>4.DevOps与Docker</h2>    <p>DevOps一词的来自于Development和Operations的组合,突出重视软件开发人员和运维人员的沟通合作,通过自动化流程来使得软件构建、测试、发布更加快捷、频繁和可靠。</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/66bb12c9cabfeaa346362907c4d3dabf.png"></p>    <p>在DevOps出现之前,软件经过开发、测试后由运维团队将发布件部署到公司的基础设施上,并将服务提供给客户使用。然而,开发、测试、运维三个团队缺少有效协同工作的机制,导致部门墙严重。开发团队往往关注新功能开发和快速迭代,而运维团队关注的是发布件的稳定性,他们不希望版本频繁的更替。往往在这两个团队间会爆发激烈的斗争。</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/92c34251e40f18d44fe7a9836fe48c58.png"></p>    <p>在DevOps出现之后,团队通过协作和自动化的方式打通了开发、测试、运维团队之间的壁垒。当有新的代码提交时,系统在第一时间会触发自动化测试,依次在开发自验环境、测试环境、运维环境中验证软件,确保可以第一时间发现软件缺陷。然而,当出现业务峰值时,传统的基础设施中的虚拟机就无法有效的应对了。</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/f08e9e72b6931b3a6607a2ab1c289d68.png"></p>    <p>在后Devops时代,随着云计算的普及,很多云平台提供了应用引擎,如果你的应用符合引擎的规范,云平台就可以自动检测业务负载量。当业务出现峰值时,平台可以利用底层容器技术的快速部署、资源快速扩展伸缩等特性来应对,从而有效的支撑了业务的正常运行。</p>    <h2>5.Docker与自动化测试</h2>    <p>对于重复枯燥的手动测试任务,可以考虑将其进行自动化改造。自动化的成本在于自动化程序的编写和维护,而收益在于节省了手动执行用例的时间。简而言之,如果收益大于成本,测试任务就有价值自动化,否则受益的只是测试人员的自动化技能得到了提升。利用Docker的快速部署、环境共享等特性,可以大大减少自动化的成本,使很多原本没有价值自动化的测试任务变为了有价值自动化的任务,大大提升了项目效率。</p>    <p>那么如果自动化测试已经运行在了虚拟机中,是否有必要使用Docker技术将其进行改造?这个就要具体问题具体分析了。笔者并不赞同将所有测试任务一刀切的进行容器化改造。如果当前虚拟机已经满足测试需求,你就需要评估一下引入Docker进行改造所需的成本,其中包含学习Docker技术所需要的时间成本。反之,如果虚拟机无法满足当前的测试需求,可以考虑尽快引入Docker进行改造。</p>    <h2>6.Docker的约束</h2>    <p>Build, Ship, and Run Any App, Anywhere.这是Docker公司高调宣称的口号,即在任何平台都可以构建、部署、运行任何应用。然而,由于Docker自身的特点,其使用场景有一些约束:</p>    <p>(1)因为容器与主机共享内核,如果容器中应用需要不同的内核版本,就不得不更换主机内核。但如果主机内核变更后又会影响到其它容器的运行。变通的方法是将应用源码的编写与内核特性解耦。</p>    <p>(2)Docker使用时需要3.10或以上版本的内核,这是最低的限制。如果你需要使用更高级的Docker特性,如user namespace,那么还需要更高版本的内核。</p>    <p>(3)使用“--privileged”选项后可以在容器内加载或卸载内核模块,但这个操作会影响到主机和其它容器。</p>    <p>(4)无法模拟不同平台的运行环境,例如不能在x86系统中启动arm64的容器。</p>    <p>(5)因为Docker采用了namespace的方案来实现隔离,而这种隔离属于软件隔离,安全性不高。不适合安全性高的测试任务。</p>    <p>(6)因为目前没有time namespace技术,修改某个容器时间时就不得不影响到主机和其它容器。</p>    <h2>7.适用于Docker的测试场景</h2>    <p>由于容器与主机共享内核使用,凡是和内核无强相关的测试任务是适合引入Docker进行改造的,例如源码编译测试、软件安装测试、互联网应用测试、数据库测试等。而与内核强相关的测试任务是不适合使用Docker进行改造的,如内核网络模块测试、内核namespace特性测试等。</p>    <h2>8.Docker测试实践</h2>    <h3>8.1.容器化编译系统测试</h3>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/0b3fb206de5ba99e5c99e75afbd887ae.png"></p>    <p>早期我们将linux发行版安装到物理机中进行测试。当需要重新进行全量测试时不得不手动还原测试环境。之后改用了虚拟机,虽然能够通过自动化的方式实现环境还原,但虚拟机的损耗较大,效率不高。</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/d3b67e8cf5e1aac1ae76af51dce4e088.png"></p>    <p>之后我们尝试将环境制作成Docker镜像,同时进行了如下的改进:</p>    <p>(1)通过Docker的“-v”选项,将主机目录映射到容器中,实现多个容器共享测试代码。测试代码部署时间从2分钟减少到10秒。</p>    <p>(2)将大粒度的执行时间较长的用例拆分成为若干个小用例。</p>    <p>(3)利用容器并发执行测试。</p>    <p>(4)使用Dockerfile梳理产品依赖包和编译软件的安装。</p>    <p>编译系统测试是用户态的测试,非常适合使用Docker进行加速。如果需要针对某一个linux发行版进行测试,可以通过Docker快速部署的特点,将所有的资源快速利用起来,从而达到加速测试执行的目的。</p>    <h3>8.2.linux外围包测试</h3>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/4b73a555df651a7a8eaaf2ffd4e487ff.png"></p>    <p>外围包包含动态链接库文件和常用的命令行工具,属于linux操作系统的中间层,其上运行着应用程序,其下由linux内核支撑。起初的外围包测试采用串行执行,效率不高。同时受到环境污染的影响,容易产生软件缺陷的误报。在改进方面,我们首先通过Dockerfile基于rootfs制作一个Docker镜像,然后通过Docker-compose工具实现测试用例的并发执行。</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/e5fa794e9e952a6dedf3c8164fc8033d.png"></p>    <p>以下是改进前后的对比。</p>    <table>     <tbody>      <tr>       <td> <p>改进前</p> </td>       <td> <p>改进后</p> </td>      </tr>      <tr>       <td>每套环境独占一台主机,主机利用率不高。</td>       <td>多套环境可以在同一主机上部署,可以更有效利用主机资源。特别是在主机资源昂贵的情况下,可以节省很多成本。</td>      </tr>      <tr>       <td>测试串行执行,因为环境污染问题测试任务不易并发。</td>       <td>通过Docker进行测试任务隔离,可以并行执行测试,提高了cpu利用率。</td>      </tr>      <tr>       <td>环境释放时清理工作依赖于程序员的技能。在每个测试用例中有一个cleanup函数,负责资源回收和环境恢复。如果程序员编程技巧不高的话,可能会造成资源回收不彻底,测试环境会受到污染。</td>       <td>环境释放时清理工作由Docker接管,当执行完任务后,可以删除容器。即使不写cleanup函数,也可以实现资源的回收。</td>      </tr>      <tr>       <td>无法解决多个外围包的环境污染问题。当连续执行多个测试时,有部分测试无法通过,而单独执行这些测试时又能够通过。这通常是由于测试环境污染造成的。</td>       <td>容器可快速启动与关闭,每次都是清洁的环境。</td>      </tr>      <tr>       <td>外围包编译环境不易统一,导致测试结果不一致。</td>       <td>通过镜像保存编译环境,确保环境统一。</td>      </tr>      <tr>       <td>测试网络包时需要至少两台主机,分别部署服务端和客户端。</td>       <td>测试网络包时只需要在同一台主机中启动两个容器来部署服务端和客户端。</td>      </tr>     </tbody>    </table>    <h2>9.通过Docker进行测试加速的原理</h2>    <p>Docker本身并不会直接加速测试执行。在串行执行测试时,在容器中执行测试反而会带来约5%左右的性能衰减。但我们可以充分利用Docker快速部署、环境共享等特性,同时配合容器云来快速提供所需的测试资源,以应对测试任务的峰值。如果忽略环境部署时间,当每个测试用例粒度无限小并且提供的测试资源无限多时,测试执行所需的时间也就无限小。</p>    <h2>10.总结</h2>    <p>很多测试任务可以利用Docker进行改造,读者可以根据项目自身的特点,因地制宜的使用Docker进行测试能力的改造。</p>    <h2> </h2>    <p>来自:http://www.infoq.com/cn/articles/docker-lead-test-innovation</p>    <p> </p>