ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

DevOps 是个神马?【实践篇2】

2021-04-09 12:57:24  阅读:197  来源: 互联网

标签:部署 环境 DevOps 应用程序 实践 验收 神马 测试 自动化


接着上篇实践篇1(https://blog.csdn.net/jinzhengquanqq/article/details/115320511),一起来看看流动的技术实践。

目录

1   配置管理

1.1  版本管理

1.2  依赖管理

1.3  软件配置管理

    1.4   环境管理

2  部署流水线

3  测试

3.1 测试策略

3.2 自动化验收测试

3.3 非功能需求的测试


创建必要的技术实践和架构,从而使开发到运维的工作能够稳定快速的流动,并确保不会造成生产环境的混乱或服务的中断,可以通过一套被称为持续交付的技术实践来实现。持续交付包括打好自动化部署流水线的基础,确保团队能够使用自动化测试持续验证代码是否处于可部署状态,保证开发人员每天都将代码提交到主干,以及构建有利于实现低风险发布的环境和代码。通过将QA人员和运维人员的任务集成到团队的日常工作中,能够减少救火、困境以及琐事的发生。

以下内容我们以开发、测试、部署的过程来介绍实践。

 

1   配置管理

配置管理是一个广泛使用的名词,往往作为版本控制的同义词。配置管理是指一个过程,所有与项目相关的产物,以及它们之间的关系都被唯一定义,修改、存储和检索。

1.1  版本管理

版本管理工具:svn、git。

版本管理内容:源代码、测试代码、数据库脚本、构建部署脚本、文档、库文件和应用软件所用的配置文件都纳入到版本控制之中,甚至把编译器以及工具等也进行版本管理,以便项目成员可以很容易地从零开始工作。

目标:能够随时获取软件整个生命周期中任意时间点的文件状态,并将系统恢复到该时间点的状态。每个项目成员都该将与项目相关的任何文件及其状态保存在版本控制存储库之中。只要能从版本控制库中取出所需要的一切,就能保证为开发、测试、甚至生产环境提供稳定的平台。

频繁提交代码到主干

      注意事项:1,只有频繁提交代码,才能享受版本控制所带来的众多好处;2,一旦将变更提交到版本控制中,那么团队的所有人都能看到这些变更,也能签出它。频繁提交,其他人可以看到你的修改且可与之交互,你也可以清楚地知道你的修改是否破坏了应用程序,而且每次合并工作的量会一直很小,易于管理。

      为了确保提交代码时不破坏已有的应用程序,有两个实践非常有效。一是在提交代码之前运行测试套件,这个测试套件应该是一个快速运转(一般少于10分钟)且相对比较全面的测试集合,以验证你没有引入明显的回归缺陷。二是增量式引入变化,我们每完成一次或一次重构之后就提交代码。

使用意义明显的提交注释:写一段简短的总结性描述,当构建失败以后,知道是谁破坏了构建,以及他为什么破坏了构建。

1.2  依赖管理

       外部文件管理:例如使用maven

       组建管理:开发软件可将软件分成多个不同的组件,当开发的时候将组件从代码库签出到开发机器上,这几个组件就应该是直接相关联的。

1.3  软件配置管理

       作为关键部件之一,配置信息与产品代码及其数据共同组成了应用程序。应该以对待代码的方式来对待你的系统配置,使其受到正确的管理和测试。

       每个人都希望使用的软件灵活,可是灵活也是有代价的。对于软件灵活性的期望常常导致一种反模式,即“终极配置”,而这种反模式常被表述为对一个软件项目的需求。

       可配置的软件并不总是像它看起来那么便宜,更好的方法几乎总是先专注于提供具有高价值且可配置程度低的功能,然后在真正需要时在添加可配置选项。配置并非天生邪恶,但需要采取谨慎的态度来一致地管理它们,对部署活动的冒烟测试就是一种缓解配置验证问题的方法,我们应该始终使用它。

        配置的分类:可以在构建、部署、测试和发布过程中的任何一点进行配置信息设置。

             构建时:在生成二进制文件时,构建脚本可以在构建时引入相关的配置,并将其写入新生成的二进制文件;

             打包时:在打包时将配置信息一同打包到软件中。

             部署时:在安装部署软件程序时,部署脚本或安装程序可以获取必要的配置信息,或者直接要求用户输入这些配置信息。

             启动或运行时:软件在启动或运行时可获取配置。

       一般来说,我们并不赞同在构建或打包时就将配置信息植入的做法,而是应使用相同二进制安装包向所有的环境中部署,以确保这个发布的软件就是那个被测试过的软件。

       应用程序的配置管理

                需要考虑如下问题:如何描述配置信息?部署脚本如何存取这些配置信息?在环境、应用程序,以及应用程序各版本之间,每个配置信息有什么不同?

                系统配置的测试:一是保证配置设置中对外部服务的饮用是良好的;二是当应用程序一旦安装好,就要在其上运行一些冒烟测试,以验证它运行正常。

        管理配置信息的原则

                  1,在应用程序的生命周期中,我们应该在什么时候注入哪些配置信息,要与系统运维和支持团队一同讨论,看看他们有什么样的需求。

                  2,将应用程序的配置项与源代码保存在同一个存储库中,但要把配置项的值保存在别处。

                  3,应该总是通过自动化的过程将配置项从保存配置信息的存储库中取出并设置好,这样就能很容易地掌握不同环境中的配置信息了。

                  4,配置系统应该能依据应用,应用软件的版本、将要部署的环境,为打包、安装以及部署脚本提供不同的配置值。

                  5,对每个配置项都英语哦给你明确的命名习惯,避免使用晦涩难懂的名称,使其他人不需要说明手册就能明白这些配置项的含义。

                  6,确保配置信息是模块化且封闭的,使得对某处配置项的修改不会影响到哪些与其无关的配置项。

                  7,定义好配置中的每个元素,使每个配置元素在整个系统中都是唯一的,其含义绝不与其他元素重叠。

                  8,最少化,即配置信息应尽可能简单且集中。

                  9,避免对配置信息的过分设计,应尽可能简单。

                  10,确保测试已覆盖到部署或安装时的配置操作,检查应用程序所依赖的其他服务是否有效,使用冒烟测试来诊断依赖于配置项的相关功能是否都能正常工作。

    1.4   环境管理

                  没有哪个应用程序是孤岛,每个应用程序都依赖于硬件、软件、基础设施以及外部系统才能正常工作。在做应用程序的环境管理时,我们需要记住的原则是:环境的配置和应用程序的配置同样重要。

          环境管理的关键在于通过一个全自动过程来创建环境,使创建全新的环境总是要比修复已受损的旧环境容易得多。

          需要考虑的环境配置如下:

                   1,环境中各种各样的操作系统,包括其版本,补丁级别以及配置设置。

                    2,应用程序所依赖的需要安装到每个环境中的软件包,以及这些软件包的具体版本和配置

                    3,应用程序正常工作所必需的网络拓补结构

                    4,应用程序所依赖的所有外部服务,以及这些服务的版本和配置信息

                    5,现有的数据以及其他相关信息

            高效配置管理策略的两个基本原则是:1,将二进制文件与配置信息分离;2,将所有的配置信息保存在一起。

            当评估第三方产品或服务时,应该考虑这样的问题:我们可以自行部署它吗?我们能对它的配置做有效的版本控制吗?如何使它适应我们的自动化部署策略?

            环境管理的工具:在以自动化方式管理操作系统配置的工具中,Puppet和CfEngine是两个代表。虚拟化技术可以轻易得到一份环境的副本,并把它作为一个基线保存起来。

             变更过程管理:对环境的变更过程进行管理是必要的,应该严格控制生产环境,未经组织内部正式的变更管理过程,任何人不得对其进行修改。任何变更在上线之前都必须经过测试,因而要将其编成脚本,放在版本控制系统中,一旦该修改被认可,就可以通过自动化的方式将其放在生产环境中。          

2  部署流水线

      持续集成实践保证创建大型复杂系统的团队具有高度的自信心和控制力,一旦代码提交引入了问题,持续集成就能为我们提供快速的反馈,从而确保我们作为一个团队所开发的软件是可以正常工作的,主要关注于代码是否可以编译成功以及是否可通过单元测试和验收测试,持续集成的主要关注对象是开发团队,输出通常作为手工测试和验收测试。

      为了使工作快速可靠地从开发流向运维,应当保证价值流的每个阶段都使用类生产环境,这些环境必须能用自动化的方式进行搭建,在理想情况下,应该使用脚本和存储在版本控制系统中的配置信息按需搭建,而不需要依赖运维团队进行手动操作,部署流水线的目标就是能够基于版本控制系统中的信息重复搭建整套生产环境。

     部署流水线是对构建以及后续一系列不同阶段的测试与部署,这一流程的建模,在持续集成和发布管理工具上,它体现为支持查看并控制整个流程,包括每次变更从被提交到版本控制库开始,直到通过各类测试和部署,再到发布给用户的过程。

     价值流图:拿着笔和纸,到你的组织中出现客户请求的地方去,你的目标就是画出从组织接到一个客户请求直至完成这一请求的一张流程图,你应该和参与每个活动的人一起,描绘出为了满足这个请求所必需的所有步骤,以及该亲求在每个步骤上所停留的平均时间,在这个图的底部,画一条时间线,标注出花在那些向该请求增加价值的活动上的时间,以及花在等待以下不增加价值的活动上的额时间。如果向做一些组织转型方面的工作来改进流程的话,你可能要深入了解每个部分由谁负责,在异常情况下的子流程是什么,各环节之间交接需要由谁审批,需要什么资源,组织级的汇报结构是什么样的等。

     代码变更经过部署流水线的过程:交付团队-> 版本控制库->构建和单元测试->自动化验收测试->用户验收测试->发布,对于用户验收测试这个过程,还可以进行容量测试。我们必需把那些用于证明某些版本满足业务要求的测试集合进行自动化,而且,还要把测试环境、试运行环境和生产环境上的部署过程自动化,这样可以避免那些手工密集型的易出错的步骤。

     最基本的部署流水线:第一个阶段(提交)会编译代码,运行单元测试,执行代码分析,创建软件二进制包,如果所有的单元测试都通过了,并且代码符合编码标注,就将可执行代码打包成可执行文件,并放到一个制品库中。第二各阶段通常由运行时间较长的自动化验收测试组成。在此之后,部署流水线可能会有分支出现,这样就可以将构建版本独立部署到多个不同的环境中,比如部署到用户验收测试环境、容量测试环境和生产环境。通常情况下,并不需要在验收测试阶段成功之后直接自动触发这些阶段,相反,我们希望让测试人员或运维人员可以做到自服务,即自己手工选择需要的某个版本,通过自动化部署脚本,并将其部署到相应的环境中。

     我们所做的一切都是为了尽快得到反馈。

     按需搭建开发环境、测试环境和生产环境:通过构建机制,任何人可以通过这种机制在几分钟内搭建好类生产环境,为了实现这一点,需要清楚定义正确环境,并将其搭建过程自动化。通过获得完全可控的环境,开发人员能在与生产服务和其他共享资源安全隔离的情况下,快速地重现、定位和修复缺陷,同时,开发人员还可以尝试更改环境和优化创建环境的基础设施代码,从而进一步在开发和运维之间共享信息。

     应用统一的代码仓库:当开发人员将所有的源文件和配置文件都纳入版本控制系统后,它就变成了唯一精确体现系统预期状态的代码仓库,然而,因为向客户交付价值同时需要代码及其运行环境,所以还需要把与环境相关的配置代码也纳入版本控制系统,版本控制系统向价值流中的所有人,通过将所有相关信息纳入版本控制系统,我们能够重复和可靠地重新生成软件系统的所有组件,这包括应用和生产环境,以及所有的预生产环境。为了确保即使在发生灾难性事故时,也可以重复且精确地恢复生产环境,必须把下列资源也纳入版本控制系统:应用的所有代码和依赖库;任何用于创建数据库模式的脚本、应用的参考数据等;所有用于搭建环境的工具和工件;任何构建容器所使用的文件;所有支持自动化测试和手动测试脚本;任何支持代码打包、部署、数据库迁移和环境制备的脚本;所有项目工件;所有云平台配置文件;创建支持多种基础设施服务。

     运行在类生产环境里才算完成:完成是指不仅实现了功能正确的代码,而且在每个迭代周期结束时,已经在类生产环境中集成和测试了可工作和可交付的代码。     

     部署流水线的相关实践:对不同环境采用同一份二进制包,同一部署方式;对部署进行冒烟测试,当做应用程序部署时,你应该用一个自动化脚本做以下冒烟测试,用来确保应用程序已经正常启动并运行了;向生产环境的副本中部署,为了对系统上线充满信心,你要尽可能在与生产环境相似的环境中进行测试和持续集成;每次变更都要立即在流水线中传递,一旦代码构建和单元测试结束,持续集成系统就去检查版本库中是否有新的提交,如果有的话,就将最近还没有构建过的所有变更全部拿来进行构建,假设这次构建和单元测试失败来,那么构建系统是无法究竟是哪个版本引起的,但开发人员自己可以很容易发现问题在哪;只要有环节失败,就停止整个流水线。

      提交阶段:一般说来提交阶段包含以下步骤:编译代码;运行一套提交测试;为后续阶段创建二进制包;执行代码分析来检查代码的健康状况;为后续阶段做准备工作。在提交阶段可设置阀值条件,不满足条件,就让提交阶段失败,比较有用的度量项包括:测试覆盖率,重复代码数量,圈复杂度,输入耦合度和输出耦合度,编译警告的数量,代码风格。把生成可执行代码作为成功的验收条件,是确保构建流程本身也能够被持续集成系统不断评估和检查的简单方法。

     自动化验收测试:验收测试阶段运行的大部分测试是功能验收测试,但不全是,验收测试阶段的目标是断言应用程序交付来客户期望的价值,并满足来验收条件,它也是一个回归测试套件,用于验证新的修改是否在现有功能中引入来回归缺陷。创建和维护自动化验收测试的流程不能由独立的团队负责,它应该是开发过程的核心组成部分,而且是由跨功能交付团队来负责的。开发人员在写单元测试和开发代码的同时,就要和测试人员与客户在一起共同创建这些测试。尽管验收测试非常有价值,但他们的创建和维护成本非常高,所以要时刻牢记,自动化验收测试也是回归测试,不要幼稚地对照验收测试条件,盲目地把所有东西都自动化。如果测试成本高于它所能节约的成本的话,不写测试也是正确的决定,然而,假如能设法改变创建和维护这些自动化测试的方式,我们可以大大削减花在这上面的精力,从而改善投入产出比。

    手工测试:在迭代开发过程中,验收测试之后一定会有一些手工的探索性测试、易用性测试和演示,测试人员会做一些机器不太擅长而人比较擅长的测试。

    非功能测试:例如容量测试或者安全测试,对于某些系统,并不需要连续不断地进行非功能测试,如果需要的话,可以在部署流水线中,创建一个阶段,用于运行这些自动化的非功能测试。

    发布准备:每次向生产环境发布时都有业务风险。我们需要:让参与项目交付过程的人共同创建并维护一个发布计划;通过尽可能多的自动化过程最小化人为错误发生的可能性,并从最容易出错的环节开始实现自动化;在类生产环境中经常做发布演练,这样就可以对这个流程及其所使用的技术进行调试;如果事情并没有按计划执行,要有撤销某次发布的能力;作为升级和撤销过程的一部分,制定配置迁移和数据迁移的策略。

    自动部署与发布:对生产环境的控制权越小,遇到意外情况的可能性就越大。生产环境应该是完全受控的,即对生产环境的任何修改都应该通过自动化过程来完成。

    变更的撤销:传统上,人们对新版本的发布常常存在着恐惧心理,原因有两个。一是害怕引入问题,二是担心由于发布过程中的一个问题或新版本的某个缺陷,使发布失败。通过每天练习发布多次来证明自动化部署系统是可以工作的。对于第二个问题,可以准备一个撤销策略。

     部署流水线的演进:随着项目越来越复杂,价值流图也会演进。对于流水线来说,还有两个常见的外延:组件和分支。每个组件都应该有一个对应的“迷你流水线”,然后再用一个流水线把所有组件拼装在一起,并运行整个验收测试集(包括自动化的非功能测试),然后在部署到测试环境、试运行环境和生产环境。首先,并不需要一次实现整个流水线,而应该是增量式实现;其次,部署流水线是构建、部署、测试和发布应用程序整个流程中有效的,也是最重要的统计数据来源,部署流水线应该记录流程的每次开始和结束时间,以及流程的每个阶段到底修改来什么。我们可以使用这些数据衡量从提交开始到将其部署到生产环境的周期时间,以及花在每个阶段上的时间,这样就可以看到整个流程的瓶颈在哪里,并根据优先级来解决它们。

      度量: 反馈是所有软件交付流程的核心。改善反馈的是最佳方式是缩短反馈周期,并让结果可视化。根据精益思想,应该做整体优化,而不是局部优化。如果你花很多时间去解决某个瓶颈,而这个瓶颈在整个交付流程中并不是一个真正约束的话,整个交付流程并不会有什么根本性的变化,因此,应该对整个流程进行度量,从而判定这个交付流程作为一个整体是否存在问题。对于软件交付过程来说,最重要的全局度量指标就是周期时间,它指的是从决定要做某个特性开始,直到把这个特性交付给用户的这段时间。

     优化流程:识别系统中的约束,也就是构建、测试、部署和发布这个流程中的瓶颈;确保供应,即确保最大限度地提高流程中这部分的产出,例如保证总是有用户故事在等待手工测试,并确保手工测试所需的资源不会被其他工作占用;根据这一约束调整其他环节的产出,即其他资源都不会100%满负荷工作,例如只要开发人员开发用户故事的速度能及时供应手工测试就可以用来,其他时间他们可以写些自动化测试来捕获缺陷,这样测试人员就不需要在手工测试上花太多时间;为约束环节扩容,如果周期时间太长,就要向该瓶颈环节增加资源;理顺约束环节重复上述步骤,即在系统中找到下一个约束。

     度量指标:自动化测试覆盖率;代码库的某些特征,例如:重复代码量,圈复杂度,输入耦合度,输出耦合度,代码风格问题;缺陷数量;交付速度,即团队交付可工作,已测试过并可以使用的代码的速率;每天提交到版本控制库的次数;每天构建的次数;每天构建失败的次数;每次构建所花的时间,包括自动化测试的时间。

    构建与部署的脚本化:为部署流水线的每个阶段创建脚本;使用恰当的技术部署应用程序;使用同样的脚本向所有环境部署;使用操作系统自带的包管理工具;确保部署流程是幂等的;部署系统的增量式演进;部署脚本化要多层的部署和测试,测试环境配置;总是使用相对路径,消除手工步骤,从二进制包到版本控制库的内建可追溯性,不要把二进制包作为构建的一部分放到版本控制库中,用集成冒烟测试来限制应用程序,“test”不应该让构建失败。

3  测试

实现快速可靠的自动化测试:如果没有自动化测试,那么我们编写的代码越多,测试代码所花费的时间和金钱也会越多。让开发人员在日常工作中创建自动化测试套件,并在开发早期就保证产品质量,这样做有利于建立快速的反馈回路,帮助开发人员尽早发现问题,并在约束最少时快速解决问题。自动化测试基础设置用于验证可部署状态,即版本控制系统中的所有内容都处于可构建和可部署的状态。

自动化测试从快到慢分为如下几类:

        单元测试:通常独立测试每个方法、类或函数。目的是确保代码按照开发人员的设计运行,由于诸多原因,通常会使用打桩的方式,隔离数据库和其他外部依赖。

        验收测试:通常整体测试应用,确保各个功能模块按照设计正常工作,而且没有引入回归错误,验收测试的目的则是证明应用能满足客户的愿望,而不仅仅是符合程序员的预期。

        集成测试:保证应用能与生产环境中的其他应用和服务正确的交互,而不再调用打桩的接口。

最快速的测试应该尽可能多地发现错误,如果大多数错误都是在验收测试和集成测试阶段发现的,那么开发人员收到反馈的速度要比单元测试发现错误时慢上好几个数量级,集成测试需要用到稀缺且复杂的集成测试环境。因此每当验收测试或集成测试发现一个错误,就应该编写相应的单元测试,以便更快、更早、更廉价地识别这个错误。

理想的自动化测试金字塔:由下往上测试数量依次减少,自动化单元测试->自动化组件测试->自动化集成测试->自动化API测试->自动化GUI测试->手动测试

要确保自动化测试可靠,最有效的一个方法是通过测试驱动开发和验收测试驱动开发等技术在日常工作中编写自动化测试。在对系统做任何变更时,都要先编写一个自动化测试用例,执行并确保测试失败,然后在编写实现功能的代码,并且让代码通过测试。

尽量将手动测试自动化、尽可能并行地快速执行测试,执行少量可靠的自动化测试,往往优于执行大量手动测试或不可靠的自动化测试,应该专注于将能验证业务目标的测试自动化,如果在放弃某个测试之后,生产环境出现缺陷,那么应该将这个测试重新加入手动测试套件,但最终还是应该将它自动化。

自动化测试套件中可集成性能测试,也可集成其他非功能需求测试。

3.1 测试策略

测试策略的设计主要是识别和评估项目风险的优先级,以及决定采用哪些行动来缓解风险的一个过程。测试的分类可参考测试四项限。

业务导向且支持开发过程的测试:这一象限的测试通常称作功能测试或验收测试,关注于功能正确性的验收测试称为功能验收测试,而非功能验收测试归于图中的第4象限。在理想情况下,客户或用户会写验收测试,因为他们定义了每个需求的满足条件,有些自动化功能测试工具,把测试脚本和实现分离,用用户来写测试脚本,开发和测试则实现这些测试脚本。

每个需求一定会找到中规中矩的执行路径,这称为Happy Path,使用“given-when-then”的模型书写,相对Happy Path,如果测试用例引发一些错误处理,称为Sad Path。测试用例的设计,可以使用等价类划分,边界值分析,经验推测。

回归测试是自动化测试的全集。在书写自动化验收测试时,应该时刻牢记,这些测试是回归测试套件的组成部分。并不是所有的东西都需要自动化,易用性测试及界面一致性等方面很难通过自动化测试来验证,尽管有时候测试人员会将自动操作作为探索性测试的一部分,比如初始化环境、准备测试数据等,但探索性测试不可能完全自动化。很多情况下,手工测试足够,甚至优于自动化测试。自动化验收测试限于完全覆盖Happy Path的行为,并仅覆盖其他一些及其重要的部分,但前提是其他类型的自动化回归测试很全面,代码测试覆盖率高于80%的测试视为“全面的”测试,测试覆盖率包括单元测试、组件测试和验收测试,每一种都要覆盖到80%。

一旦对同一个测试重复做过很多次手工操作,并且你确信不会花太多时间来维护这个测试时,就要把它自动化。

需要写的最重要的自动化测试是那些对Happy Path的测试,每个需求或用户故事都应该有对Happy Path的自动化验收测试,而且应至少有一个,这些测试应该被每位开发人员当作冒烟测试来使用,从而能够为“是否破坏来已有的功能”提供快速反馈。当你有时间写更多的自动化测试时,很难在Happy Path和Sad Path之间进行选择,如果应用程序比较稳定,那么Alternate Path应该是你的首选,因为他们是用户所定义的场景。如果你的应用程序有较多的缺陷并且经常崩溃的话,那么战略性地应用对Sad Path的测试会帮助你识别那些问题域并修复他们,而且自动化可以保证应用成保持在稳定状态。

技术导向且支持开发过程的测试:单元测试、组件测试和部署测试,这些自动化测试单独有开发人员创建并维护。单元测试常常依赖于测试替身模拟系统其他部分,单元测试不应该访问数据库、使用文件系统、与外部系统交互,单元测试不应该有系统组件之间的交互。组件测试用于测试更大的功能集合,比如需要链接数据库、文件系统或其他系统。每当部署应用程序时,要执行部署测试,检查部署过程是否正常,就是应用程序是否被正确安装、配置,是否能与所需的服务正确通信,并得到相应的回应。

业务导向且评价项目的测试:这类手工测试可以验证我们实际交付给用户的应用软件是否符合其期望,这并不知识验证应用是否满足需求规格说明,还验证需求规格说明的正确性。一种非常重要的面向业务且评价项目的测试是演示,在每个迭代结束时敏捷开发团队都向用户演示其开发完成的新功能,确保尽早发现对需求规范的错误理解或有问题的需求规范。探索性测试可以是一种手工测试,一个创造性学习过程,并不只是发现缺陷,它还会致使创建新的自动化测试集合,并可以用于覆盖那些新的需求。易用性测试是为来验证用户是否能很容易地使用该应用软件完成工作。

技术导向且评价项目的测试:验收测试分为两种:功能测试和非功能测试。非功能测试是指除功能之外的系统其他方面的质量,比如容量、可用性、安全性等。

测试替身

    哑对象:是指那些被传递但不被真正使用的对象,通常这些对象只是用于填充参数列表。

    假对象:是可以真正使用的实现,但是通常会利用一些捷径,所以不适合在生产环境中使用,一个很好的例子是内存数据库。

    桩:是在测试中每个调用提供一个封装好的响应,它通常不会对测试之外的请求进行响应,只用于测试。

    spy:是一种可记录一些关于他们如果被调用的信息的桩,这种形式的桩可能是记录它发出去了多少个消息的一个电子邮件服务。

    模拟对象:是一种在编程时就设定了它预期要接受的调用,如果收到了未预期的调用,他们会抛出异常,并且还会在验证时被检查是否收到了他们所预期的所有调用。

现实中的情况与应对策略

     新项目:一开始就要写自动化验收测试。需要:选择技术平台和测试工具;建立一个简单的自动化构建;制定遵守INVEST原则[独立的、可协商的、有价值的、可估计的、小的且可测试的]的用户故事及其验收条件。参考流程:客户、分析师和测试人员定义验收条件;测试和开发一起基于验收条件实现验收测试的自动化;开发人员编码来满足验收条件;只要有自动化测试失败,无论是单元测试、组件测试还是验收测试,开发人员都应该把它定位高优先级并修复它。对于每个验收条件来说,都应该能写出一个自动化验收测试来证明项目交付来用户所需的价值。

    项目进行中:引入自动化测试最好的方式是选择应用程序中那些最常见、最重要且高价值的用例为起点,与客户沟通,以便清楚地识别真正的业务价值是什么,然后使用测试来做回归,以防止功能被破坏,基于这些沟通,你应该能把那些Happy Path的测试自动化,用于覆盖高价值的场景。

    遗留系统:没有自动化测试的系统就是遗留系统。要聚焦于系统中高价值的功能,创建回归测试套件的价值在于保护系统当前的功能。对于遗留系统来说,这些覆盖核心功能的测试就是非常重要的冒烟测试了。一旦有了这些冒烟测试,就可以开发新的用户故事了,这时候,把自动化测试分成了不同的层级也是很有用的,第一级应该是那些非常简单且运行较快的测试,而且这些测试要能验证那些妨碍你手中的功能进行开发或做测试的问题。第二级是测试某个具体用户故事的关键共功能。

    集成测试:是指那些确保系统的每个独立部分都能正确作用于其依赖的那些服务的测试。可以利用写一般验收测试的方式来写集成测试,集成测试应该在两种上下文中进行:首先是被测试的应用程序使用其真正依赖的外部系统来运行时,或者是使用由外部服务供应商所提供的替代系统;其次是应用程序运行于你自己创建的一个测试工具之上,而且这些测试用具也是代码库的一部分。

3.2 自动化验收测试

验收测试在部署流水线中是一个关键阶段:它让交付团队超越来基本的持续集成,一旦正确实施自动化验收测试,你就是在测试应用程序的业务验收条件,即验证应用程序是否为用户提供来有价值的功能。验收测试通常实在每个已通过提交测试的软件版本上执行的。对于一个单独的验收测试,它的目的是验证一个用户故事或需求的验收条件是否被满足,验收条件有多种类型,如功能性验收条件和非功能性验收条件,非功能性验收条件包括容量、性能、可修改性、可见性、安全性、易用性等等。验收测试即验证来应用程序是否交付来用户期望的业务价值,又能防止回归问题或缺陷破坏了应用程序的原有功能。

通过合理的创建和维护自动化验收测试套件,其成本就会远低于频繁执行手工验收和回归测试的成本,或者低于发布低质量软件带来的成本。

单元测试和组件测试都不测试用户场景,因此也无法发现那种用户与应用程序进行一系列交互后呈现出来的缺陷。验收测试就是为这个设计的,另外,验收测试在以下几个方面也表现出不俗的差错能力:线程问题,已事件驱动方式实现的应用程序出现的紧急行为,以及由架构问题或环境及配置问题造成的其他类型的bug,这类缺陷很难通过手工测试发现,更不用说单元测试和组件测试了。

如何创建可维护的验收测试套件:验收测试来源于验收条件,写应用程序的验收条件时必须想着如何使其自动化,并遵守INVEST原则,尤其是“对最终用户有价值”和“可测试”这两点。一旦拿到来一些验收条件来描述对用户的价值,下一步就是将它们自动化。自动化验收测试应该是分层的,第一层就是验收条件,第二层是测试实现层,第三层是应用程序驱动层(应用程序驱动层是一个知道如何与应用程序打交到的层次,应用程序驱动层所用的API是以某种领域语言表达的,可以认为是一种针对它自己的领域专属语言)。

创建验收测试:首先,分析人员、测试人员应该和客户一起,确定验收条件,然后在讨论某种可以自动化的方式展现这些验收条件。将验收条件变成可执行的规格说明书,验收测试就是正在开发的应用程序行为的一个可执行规格说明书,这作为自动化测试的一种新方法,被称为行为驱动开发,行为驱动开发的核心理念之一就是验收测试应该以客户期望的应用程序行为的方式来书写,这样,就可以拿这些写好的验收条件直接在应用程序之上运行,来验证它是否满足规格说明。

验收测试中的状态:这里的“有状态”是指为了测试应用程序的某个行为,应用程序必须处于某种特定的起始状态。虽然在所有的测试中消除状态是不切实际的,但更重要的是让测试对复杂状态的依赖最小化。首先,要抵制使用生产数据的备份作为验收测试数据库的诱惑,相反,我们要维护一个受控的数据最小集。毕竟,测试的关注点在于系统的行为,而非数据本身。维护一个最下的一致性数据集,足够让你做探索系统的行为就可以了,很自然地,这个最小的起始点应该是放在版本控制库中的一组脚本,在验收测试开始运行时使用。最理想的测试应该具有原子性,原子测试是指测试的执行顺序无关紧要,这样就消除了那些很难追踪的bug的主要来源之一。而且,这也意味着测试可以并行执行,只有做到这一点,你才能做到,无论应用程序变得多么庞大,都能得到快速反馈。原子测试会创建它所需要的一切,并在运行后清理干净。验收测试最有效的方法是:利用应用程序自身的功能特性来隔离测试的范围。有时只能在测试用例间共享状态,在这种情况下,必须细心地对测试进行设计,像这样的测试更脆弱,因为他们的起始点并不是明确的。如果在测试最后没有环境清理过程的话,执行多个测试时,就无法重复运行他们。当你发现必须创建一个无法初始状态而且运行后也无法清理干净的测试时,建议集中精力,让这样的测试有绝对的防御性,在测试开始之前验证其状态是否符合你的期望,如果有任何异常之处,就马上让这个测试失效,用前置条件断言来保护测试,确保系统已为运行该测试准备好了,对于这种测试,要以相对方式验证,而不是绝对方式。

过程边界、封装和测试:自动化测试让你的代码更趋向于模块化和更好的封装性,但是如果你通过破坏封装性让它变得可测试,那么通常就会错过达到同一目的的好方法。测试代码的存在只是为了验证应用程序的行为,努力避免这种受限访问,为自己设定一个底线,努力思考,直至你非常肯定自己已无法再找到更好的方法之前,决不放弃,当一点灵感都没有的时候,你就不得不使用某种后门了。只要能依赖系统自身的真正行为来验证测试的结果,就尽量避免这种妥协,只有没有其他选择时,才启用这种策略。

管理异步与超时问题:异步系统的测试有其独特之处,就单元测试来说,在单个测试范围之内,应该避免所有异步情况,也要避免跨越测试边界的情况。后者会引起难以发现的偶然性测试失败,对于验收测试来说,根据应用程序本身的特点,异步可能是不可避免的。最有效的策略是构建一个夹具用于将测试本身与这个问题隔离开来,诀窍是,对于测试本身而言,让事件顺序发生,使测试看起来像是同步的,这可以通过把同步调用背后的异步性隔离开来实现。

使用测试替身对象:能够在生产环境自动化测试是做验收测试的必备条件,然而,这种测试环境的一个关键属性是它能够完全支持自动化测试,自动化测试与用户验收测试并不完全一样,其中一个不同点就是:自动化验收测试不应该运行在包含所有外部系统集成点的环境中,相反,应该为自动化验收测试提供一个受控环境,并且被测系统应该能在这个环境上运行,“受控”是指,可以为每个测试创建正确的初始化状态,如果与正在的外部系统集成,我们很可能就无法做到这一点。在做验收测试时,应该最小化外部依赖的影响。

为外部集成点的行为编写测试:测试点应该是那些可能出现问题的点,而到底哪些点容易出现问题更多地是由该集成自身的特性以及外部系统在整个生命周期中所处的位置决定的。假如外部系统比较成熟并且已经上线,那么出现的问题可能与正在开发当中的系统遇到的问题有所不同。如果外部系统也在开发中,那么两个系统间的接口很可能会修改,模式和契约等都可能改变,在这种情况下,需要定期做仔细的测试,来识别两个系统的临界点,在大多数集成活动中,通常有几个明显的场景需要模拟,建议编写少量测试来覆盖这些场景,一旦发现遗漏问题,就写个测试来把它补上,这种策略并不完美,但在这种情况下试图做到完全覆盖的话,通常是非常困难的,而且投资回报率很小。测试应该总是被限定在两个系统之间的特定交互上,不应该对外部系统接口进行全面测试,基于收益递减规律:如果你根本不在一某个特定的字段是否有值,就别测试它了。而缓解策略就是实现它自己的测试套件,这样就不用每次验收测试运行时就运行它,但最好还是一天或一周运行一次,你也可以将这些测试放在部署流水线的另一个阶段中,比如放在容量测试阶段。

一旦有了验收测试套件,就应该把它作为部署流水线的一个组成部分来运行,确保验收测试一直处于通过状态。

我们常常选择运行一小撮冒烟测试,用于断言我们配置的环境与期望一致,并且系统中各种组件中的通信也是正常的,有时把这叫做集成设施测试或环境测试,但实际上,他们是部署测试,目的在于证明部署非常成功,并为更多功能验收测试的执行建立完好的起始状态。

验收测试的性能:重构通用人物,共享昂贵资源,并行测试,使用计算网络,让验收测试更快。

3.3 非功能需求的测试

非功能需求的测试,主要是关于容量、吞吐量和性能的测试。“性能”是处理单一事务所花时间的一种度量,即可以单独衡量,也可以在一定的负载下衡量。“吞吐量”是系统一定时间内处理事务的数量,通常它受限于系统中的某个瓶颈。在一定的工作负载下,当每个单独请求的响应时间维持在可接受的范围内时,该系统所能承担的最大吞吐量被称为它的容量。

非功能需求与功能测试同样重要,同样有价值,它也是系统功能中至关重要的组成部分。

由于在交付过程的后期很难对系统架构进行修改,所以在项目一开始就要考虑非功能需求,这是至关重要的。可以同时使用以下两种方法:创建一些具体任务来管理非功能需求;如果有必要,向其他功能需求中加入非功能需求的验收条件。

对于容量问题,可以以用户故事的方式定量描述系统在这方面的期望是合理的,并且要定义足够多的细节,这样就可以做成本与收益的分析,并依此对他们进行优先级的排定了。

假如没有很好地分析非功能需求,它们就往往会限制我们的思维,从而导致过分设计和不恰当的优化。很容易花过量的时间写一些“高性能”的代码。

在97%的时间里,我们都应该忘记那种小的效率提升:过早优化是所有罪恶之根,我们也不能让另外非常关键3%的机会与我们擦肩而过。

在找到解决方案之前,必须先找出问题的根源,容量测试阶段的关键在于,它要告诉我们是否存在问题,以便我们可以修复它。

过早且过分地关注应用程序的容量优化是低效且昂贵的。事实上,根据需要,为高容量系统写的代码比日常系统的代码要更简单,复杂性增加了延迟。现代软件系统中,最昂贵的是网络通信或磁盘存储,在性能和应用程序的稳定性方面,跨进程或网络边界的通信是昂贵的,所以这类通信应该尽量最小化。

与写其他类型的系统相比,写高容量系统需要有更严格的要求,也需要对底层软硬件如何对应用程序提供支持有一定程度的了解,高性能需求也带来了额外的成本,而我们必须理解和权衡这种附加成本所带来的业务价值,对容量的关注常常迎合了技术人员的心理,这对我们是不利的,很可能导致解决方案的过度设计,从而增加项目成本,因此,让业务干系人决定系统的容量特性是及其重要的。我们再次重申一个事实,即高性能的软件实际上比较简单,而不是更复杂,问题在于我们要做一些工作,为它找到一个更简单的解决方案。

容量度量:容量度量要广泛研究应用程序的特征。

          扩展性测试:随着服务器数、服务或线程的增加,单个请求的响应时间和并发用户数的支持会如何变化。

          持久性测试:这是要长时间运行应用程序,通过一段时间的操作,看是否有性能上的变化,这类测试能捕获内存泄露或稳定性问题。

          吞吐量测试:系统每秒能处理多少事务、消息或页面点击。

           负载测试:当系统负载增加到类似生产环境大小或超过它时,系统的容量如何?这也许是最典型的容量测试。

容量测试的一个重要方面是能够为给定的应用程序模拟真实的使用场景。

在容量测试策略中还要包含基于场景的测试,把系统的一个具体使用场景作为一个测试,并且根据业务上对真实环境中的预测值对其进行评估。每个基于场景的测试都应该能够与包含其他交互操作的容量测试同时进行,为了更加高效,可以将容量测试组成多个大范围的测试套件,然后并行执行。完全复制真实生产环境的流量是不可能的,所以需要做流量分析,并结合经验和直觉来达到尽可能接近于真实环境的模拟。

如何定义容量测试的成功与失败:首先,把目标设定为得到稳定、可重现的结果。然后,一旦某个测试通过了最低验收标准,就把验收标准提高一点,调整该测试的成功门槛。

自动化容量测试:代码的修改对系统容量的影响与其对功能的影响一样重要。当做了修改之后,要尽早掌握容量会下降多少,这样就能快速且有效地修复它,这就要在部署流水线中假如一个阶段,即容量测试阶段。如果想在部署流水线中增加容量测试的话,就应该创建一个自动化容量测试套件,并且每次对系统进行修改之后,一旦通过了提交测试和验收测试,就应该执行容量测试。如果能记录下测试与系统的交互,并将其复制多次,然后重新播放这些被复制的交互,那么就可以在系统上加载多种负载进行测试,同时也测试了多个场景。基于服务或公共API来录制交互操作,使用录制的交互模版进行容量测试。

使用容量测试桩开发测试:对高性能系统来说,写容量测试的复杂度往往超过为了通过这些测试而写出足够快的产品代码的复杂度。所以,要解决一个至关重要的问题,那就是确保每个测试的自身运行速度非常快,足以用来判定被测试的产品代码的性能是否达到要去。无论你在什么时候写容量测试,一定要先实现一个被测试应用程序、接口或技术的桩,而且这个桩一定要非常简单且无操作,这样你才能展示出该测试满足所需的运行速度,并且当另一端无操作时可以正确地断言,该测试可以通过。

将容量测试加入到部署流水线中:大多数容量测试不适合放在部署流水线的提交阶段,因为它们通常需要的时间太长,资源暂用太多,如果容量测试相当简单,并且花的时间不长,可以将其增加到验收测试阶段,尽管并不建议这么做。

创建一组全面的自动化测试,用来确保构建始终处于绿色的可部署状态,在部署流水线中组织好测试套件和测试活动,建立规范,要求无论谁的代码变更导致自动化测试失败,大家都要竭尽全力地将系统恢复到绿色状态。

 

标签:部署,环境,DevOps,应用程序,实践,验收,神马,测试,自动化
来源: https://blog.csdn.net/jinzhengquanqq/article/details/115353649

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有