😏作者简介:博主是一位测试管理者,同时也是一名对外企业兼职讲师。
📡主页地址:【Austin_zhai】
🙆目的与景愿:旨在于能帮助更多的测试行业人员提升软硬技能,分享行业相关最新信息。
💎声明:博主日常工作较为繁忙,文章会不定期更新,各类行业或职场问题欢迎大家私信,有空必回。
阅读目录
- 1. 前言
- 2. 云原生的崛起
- 3. 云原生应用
- 4. 云原生应用测试的挑战
- 5. 云原生应用测试实践
- 5.1 单元测试
- 5.2 集成测试
- 5.3 端到端测试
- 5.4 持续集成和持续交付
- 5.5 契约测试
- 5.6 混沌工程和失效模式测试
- 5.7 失效模式测试
- 5.8 混沌工程与失效模式测试的结合应用
- 5.9 可观察性、监控和日志分析
- 5.10 可观察性
- 5.11 监控
- 5.12 日志分析
- 6. 后话
1. 前言
在当今数字化时代,云计算已经成为许多企业提高效率、灵活性和创新的关键驱动力。随着云计算的不断普及,云原生应用程序的开发和部署已成为软件行业的主要趋势。然而,尽管云原生应用有着巨大的潜力,但在其开发和维护过程中,仍然存在许多挑战。今天我们将深入地探讨云原生应用测试与质量保障的重要性,以及有效的实践方法。
2. 云原生的崛起
其实云原生应用的兴起可以追溯到云计算技术的演进,当下云计算已经改变了企业管理和应用程序开发的方式。它提供了灵活性、可扩展性和成本效益,使企业能够更好地应对不断变化的需求和市场趋势。
云计算平台,现如今主流的有阿里、腾讯、华为、AWS、Azure和GCP,为企业提供了强大的基础设施和服务,使它们能够更轻松地构建和部署各自的应用服务。在云计算的支持下,云原生应用也迅速崭露头角,成为了广大企业的新宠儿。
云原生应用可以说是一种特殊类型的应用程序,是为在云环境中构建和运行而设计。这些应用通常以微服务架构的形式存在,这意味着它们由多个小型、独立部署的服务组成,这些服务可以独立扩展和更新。这种架构往往用着着三高的特性(高可用、高性能、高扩展)以及更快的交付周期。
3. 云原生应用
那么说了这么多的云原生的优势,那基于云原生部署而成的应用到底有着什么样的优势与能力呢?接下来我们就一起来看一下吧。
微服务:云原生应用通常采用这种架构,其实就是将应用程序划分为多个小型、独立的服务。每个微服务都有自己的代码库和数据存储,可以独立开发、部署和扩展。正是这种松散耦合架构,才可以令应用有用极高的可维护性和灵活性。
容器化:容器技术,相信大家也已经早已耳熟能详了,比如主流的Docker,也在云原生应用中得到了广泛应用。每个微服务通常被打包成一个独立的容器,其中包含运行时所需的代码和依赖项。使用容器的最主要目的就是为各个服务提供了一种一致的运行环境,使应用程序在不同的云平台上都能够正常运行。
动态编排:云原生应用使用容器编排工具,比如k8s来管理容器的部署和伸缩。这些工具允许自动化应用程序的部署、监控和扩展,以适应变化的工作负载。
持续交付:CI/CD也是云原生应用的老朋友了,它允许开发人员频繁地提交代码并自动构建、测试和部署应用程序。有助于减少发布周期,提高交付速度。
通过以上的这些特性与优势,我们其实就可以看出云原生应用为何会被广大的企业作为自身业务服务形态的不二之选了。其实离开项目开发的层面,对于一款产品来说云原生本身也有着成本效益与安全性等其他的优势,相较于以前传统的部署方式与产品服务形态来说是有过之而无不及。
4. 云原生应用测试的挑战
尽管云原生应用的发展给企业带来了众多好处,但它的出现也在自然引入了新的挑战,特别是在产品保障与测试方面。众所周知,传统的单体应用程序通常比较容易测试,因为它们在一个相对简单的部署环境中运行,有固定的代码库和依赖。而云原生应用通常在更复杂、分布式的环境中运行,其中存在大量的独立微服务和动态资源分配。
基于云原生的基础特性,一般来说测试的同学都会遇见以下这些问题:
-
微服务架构:如果涉及到后端平台测试,由于云原生应用通常由多个微服务组成,每个微服务都有自己的代码库和数据存储。所以这种分散的架构增加了测试的复杂性,每个微服务都必须独立测试,同时还需要测试它们之间的交互。
-
快速迭代:其开发通常采用敏捷和DevOps方法,这意味着版本的迭代更新和部署速度非常快。这样的快速迭代要求测试团队能够快速适应变化,保持测试用例和流程的实时性,并拥有良好的自动化测试手段。
-
复杂的环境:云原生应用程序通常在多个云服务提供商的环境中运行,这增加了测试环境的多样性和复杂性。测试团队必须能够模拟不同的云环境,并确保应用程序在各种情况下都能正常工作。
-
故障模式:基于云原生应用的复杂性,故障模式变得更加多样化和难以预测。测试团队与运维团队需要识别和模拟各种故障情况,以确保应用程序具有弹性和可恢复性。
-
监控和可观察性:在云原生环境中,监控和日志记录变得至关重要。测试团队必须有效地监控应用程序的性能和状态,并能够分析日志以快速定位问题。
知晓了以上的种种之后,当我们在面对这些挑战时,同样的就不能采用以前的一些单一的测试老方法来开展质量保障活动。而应该知己知彼,根据这些独有的产品与环境特性来进行新的测试工具与手段的实践。
接下来,我们将探讨一些有效的测试方法和最佳实践。
5. 云原生应用测试实践
5.1 单元测试
单元测试是云原生应用开发中的基石。它们用于验证应用程序的各个单元或组件是否按预期工作。每个单元测试关注一个小而独立的部分,一般是一个函数、方法或微服务。但是云原生应用中的单元测试却与传统的有些不同,前面我们也已经说过了云原生的一些优势,其中就可以借助微服务与容器化的特性来进行快速且频繁的单元测试,开发人员的测试频率与维度也更为的灵活,很多时候单元测试只会测试正向场景与简单功能实现,而有了刚才所说的这些特性,开发可以尝试更多的可能性与破坏性探索测试,当然这也是在测试适当介入且时间较为充裕的情况下。另外因为频率更高的关系,当出现问题时开发人员也可以更加快速的得到及时反馈,而问题出现的定位也会因为微服务各项服务模块独立的关系而更加的清晰。当然好处不单单仅此而已,由于大家是独立开发各项服务或小模块,单元测试的测试代码编写难度与成本也更为的低。
5.2 集成测试
集成测试相信是各位测试同学的拿手好戏了吧,它关注不同组件之间的互操作性和通信。在云原生应用中,各个微服务和容器化组件必须能够协同工作,以提供完整的应用功能。说到服务,那么接口测试必不可少,用它来验证不同组件之间的接口和通信方式与数据准确性;当然因为云原生应用的微服务由于是独立开发和部署的,所以版本控制也需要做到严格的控制,确保不同版本的微服务之间可以互相兼容与正常工作;另外一个关注点则是服务所需组件的依赖关系,除了整体的管理机制之外还需要测试人员对不同的依赖进行模拟与测试组合。如果上述的这些放在传统的部署环境中一定会遭到大部分从业人员的反对,值得庆幸的是在云原生中我们可以借助k8s等工具来快速部署应用的不同部分,并模拟实际生成环境中的操作与测试场景。
5.3 端到端测试
端到端测试是测试云原生应用的最终验证层。这个测试活动的目的是模拟完整的用户路径和工作流程,以确保应用程序在实际使用中正常工作。前面的几类测试已经将所有的服务与交互进行了一个验证,这里就需要从客户端出发,根据测试策略与场景、测试用例中所指定的条件来验证整个应用的用户场景,而不仅仅是再关注单个组件与微服务,打个比方,从用户登录到执行特定操作的完整路径就是端到端测试的一个简单用户场景,我们需要关注这条路径中的所有操作、数据、交互等组成因素的正确性。从其他角度来思考的话,单单确保功能的正确性还远远不够,这里还需要将性能与安全因素考虑进去,比如整体服务以及程序在压力下仍然能够提供快速响应、对潜在威胁的抵御能力。但真实的执行过程中我们无法全面的关注上面所说的所有的因素,无论是受限于团队规模、时间成本、资源预算等,所以我们需要在手工的基础上加入一定质量保障的自动化测试工具与脚本,除了可以有效的提升测试效率之外,也可以将重要的人力资源放置在重要的功能模块与服务上,有了多维的手段相辅相成之后,才可以有效的确保测试覆盖所有必要的方面。
5.4 持续集成和持续交付
在不断的版本迭代的过程中CI/CD也是不可或缺的实践。CI/CD流程有助于自动化测试和部署,确保代码的频繁交付和快速反馈。如何提高自动化测试的执行效率与落地性价比,CI/CD自然是不二之选,无论是单元、集成还是端到端,我们只有通过所有的测试活动之后产品版本才可以正是上线。那么原有的人工步骤或需要人工触发的自动化步骤都可以集成进CI/CD环境中,确保大部分的重复性步骤都可以快速及时的自动化执行。另一方面,由于测试的过程中需要部署不同的服务与测试场景,依托于CI/CD我们也可以快速的部署各类环境以减少发布周期。即使发布或代码迭代的过程中发现问题,也可以及时混滚,确保快速修复与降级。
5.5 契约测试
在云原生应用中,有一种特别的测试活动类型叫契约测试,它已然渐渐成为了确保微服务组件的互操作性和稳定性的关键方法。这个测试策略通过验证服务之间的合同,确保它们按照预期进行通信,从而降低了集成问题的风险。
这就是契约测试的作用。契约测试是一种测试策略,用于验证服务之间的通信是否遵循一组约定,这些约定定义了输入和输出的格式、协议、数据类型等。在微服务架构中,这些约定通常以API契约的形式存在,描述了服务之间的通信方式。契约可以是接口定义语言(IDL)文件、OpenAPI规范、GraphQL模式等。它会确保服务提供者和服务消费者之间的通信遵循这些契约。模拟服务提供者的行为,以确保其提供的数据与契约一致。在契约测试中,测试用例是基于契约生成的,测试执行的目标是验证服务是否满足这些契约。如果服务提供者或服务消费者更改了其行为,契约测试将能够检测到这些变化并发出警告。
契约测试与传统集成测试不同的地方在于传统测试需要模拟整个应用程序的行为,而契约测试将关注点集中在服务之间的通信上,简单的来说就是简化了测试过程。而且契约测试的主要目的就是确保服务之间的稳定通信,防止不一致的通信表现并减少集成问题的风险。当然同样的将契约测试集成在CI/CD环境中也是一个非常不错的选择。
在现有的技术框架的支持下,契约测试可以对一些主流的微服务架构、API集成与网关、GraphQL服务等进行测试验证。
5.6 混沌工程和失效模式测试
在现有的云原生应用的生态系统中,服务的稳定性和可靠性是至关重要的。虽然微服务分散部署,相互协作以提供高度复杂的功,但是这种分布式系统也引入了许多潜在的问题和不确定性。为了确保云原生应用的服务稳定性,混沌工程和失效模式测试就成为了至关重要的工具。
混沌工程
混沌工程,源自Netflix的Chaos Monkey工具,是一种测试方法,通过故意引入故障和混乱来评估分布式系统的稳定性和弹性。这种方法的核心理念是:在生产环境中,不是“如果”而是“当”故障发生。通过主动引入故障,团队可以识别系统中的弱点,改进故障处理机制,并提高系统的可用性。
混沌工程的目标是模拟现实世界中的故障条件,从而帮助团队更好地理解系统的行为和性能。一般企业中会由专业的测试团队来进行这项工作,团队会使用混沌工程工具(如Chaos Monkey)来进行模拟,而工具会随机终止云实例来模拟云服务中的硬件故障。同时团队也会进行各类针对应用服务的混沌工程试验,这类实验主要是测试系统在异常情况下的表现,包含但不限于模拟网络延迟,硬件故障,服务崩溃等。不过像混沌工程这样规模的工程试验一般都需要强大的监控和度量系统,它们需要在应用服务与硬件故障的条件下进行各类表现的记录,用于分析系统的弹性与稳定性。
当然混沌测试也不是任意而为之的,它的设计与执行必须建立在一定的准则之上,比如模拟的场景必须是真实世界中可能发生的故障,这就需要设计人员真实的采集整理过相关的故障报告与数据;测试过程中的被测对象通常会被随机选择,但也必须按照最小化破坏的目标来进行;执行试验的过程也需要是自动化的,一是为了确保测试的可重复性,二是减轻人工干预的风险;最后则是需要及时跟踪与报告被测系统的状态与数据,正如之前上面所提的,需要强大的监控与度量系统来介入,单以人工的方式来记录与报告是完全没有可行性的。
5.7 失效模式测试
失效模式测试是一种系统测试方法,旨在识别和评估系统中的潜在失效模式和故障条件。失效模式是指系统中可能发生的不希望的事件或行为。它有助于提前发现潜在的问题,以采取措施来减轻或消除这些问题。
与混沌工程类似,我们在执行失效模式测试活动的过程中一样需要遵顼其对应的执行流程。首先产研团队需要对涉及到的系统进行分析与涉及审查,用以识别可能的失效模式,一般包含硬件故障、软件错误、设计缺陷等;当识别完成并记录在档后,执行团队就可以通过软件错误注入、硬件故障模拟或其他方式来故意引入失效模式或模拟失效条件,在这样的情况下一旦失效模式注入完成,团队可以得到当初所需要收集的系统表现与数据并且评估系统的反应;最后团队会根据最终的系统影响评估与问题列表来采取对应的措施以修复或改进系统的设计,最终达到提高系统稳定性和可用性的目的。
5.8 混沌工程与失效模式测试的结合应用
在实际的行业情况中,混沌工程和失效模式测试通常结合应用,以确保系统的弹性和可靠性。混沌工程通过引入故障来测试系统的实际行为,而失效模式测试则专注于潜在的失效模式和故障条件,这两种方法的结合可以提供全面的系统测试。
当混沌工程引入故障时,失效模式测试可以评估系统在这些故障条件下的表现。这有助于团队了解系统的弱点,并采取措施来改进系统的设计和实施。
举个例子,一个云原生应用,团队使用混沌工程工具模拟了数据库故障。在这种情况下,失效模式测试可以用于评估应用程序在数据库故障条件下的行为。团队可以观察应用程序是否能够正确处理数据库故障,并在数据库恢复后继续正常运行。如果发现问题,团队可以修复这些问题,以提高应用程序的可靠性。
5.9 可观察性、监控和日志分析
在构建和维护云原生应用程序时,了解应用程序的运行状况、性能和可用性至关重要。而测试人员在整个测试活动的过程中会产生的许多相当有用的信息,这些信息可以为产品的迭代提供有效的规划。
5.10 可观察性
可观察性是指对应用程序的运行状态、性能和行为进行全面监测和分析的能力。有了可观察性,我们就可以洞察应用程序内部的运行状况,发现潜在问题,并了解用户与应用程序的互动方式。当然无论是上线前还是上线后的测试活动,我们都必须仔细的留意数据与信息的产生,如果测试没有按照正确的方式安全地进行,则产生出的信息也将毫无价值。
可观察性对于确保应用程序的可用性、性能和安全性有着莫大的意义。我们可以通过观察性快速的发现和诊断潜在的系统故障与问题,从而帮助开发更效率的解决它们;如果从性能的角度出发,观察性还可以帮我们更好的了解应用程序的性能有瓶颈,有助于进行性能优化与改进。
那我们如何在施行观察性?其实从以下几个方面可以让我们介入;第一,进行有效的日志记录,应用程序生成的详细日志、关键事件、错误和警告等,都是我们排查问题和分析性能的切入点;第二,通过指标和仪表板等呈现方式来对关键性能指标进行量化,还可以实时检测应用系统的性能,包含吞吐、延迟、错误率等等;第三,对于微服务架构来说,分布式追踪监控方式是一个不错的选择,它可以从一个服务请求跟踪到另一个服务,以了解请求的路径和性能;第四,设置警报,以便在应用程序出现问题时及时通知团队。这有助于及早采取行动,以减小潜在的影响;第五,进行安全审计,通过此方式我们可以了解谁访问了应用程序以及用户进行了哪些操作,对于统计和形成用户行为数据非常有效;第六,事件记录,通过这一方式我们可以记录事件和活动,从而了解应用程序内部的状态和行为。
5.11 监控
监控是可观察性的关键组成因素之一,它涉及实时追踪应用程序的运行状况和性能。监控不仅可以帮助团队及时发现问题,还可以提供有关应用程序的持续性能数据。
基于一些主流的监控系统与手段,我们完全可以根据自己的业务选择实施监控需要选择适当的工具和指标,并将其集成到应用程序中,如Prometheus、Grafana、New Relic。有了这些工具与手段的加持,我们就需要定义关键性指标,当然这些都是可以进行完全的自定义的,以监控应用的健康状态;实时告警与日志则与观察性的一致,这里就不展开介绍了;另外我们可以将一些修复操作与排错操作编写成脚本实现自动化反应机制,这样相对起单独监控的行为来说要来的有效很多,也避免了不少较为被动的局面出现。
5.12 日志分析
日志分析是可观察性的另一个关键组成因素,它涉及分析应用程序生成的日志以了解应用程序的行为和问题。
相对于监控来说,日志分析则是处于相对靠后的阶段行为,但是它也有着非常重要的意义,我们通过日志分析,可以清晰的了解应用中的问题与错误成因,更甚者可以通过某些信息来预防一些潜在的安全威胁。
日常工作中一般对于日志的分析动作我们都可以从以下几个角度切入,第一,将日志中的事件进行详细的分类,包括关键事件、错误、警告和信息,这个系统中的自带日志分类可能无法很好的契合各自的业务,这里就需要开发人员进行有针对性的日志系统开发来定制满足;第二,日志的存储尽量使用集中存储,方便团队成员可以快速的访问与分析;第三,配置一些实时分析工具,例如ELK、Splunk等;第四,告警与仪表板也是必不可少的,将关键数据可视化,方便在日志中发现特定事件并及时通知团队;第五,某些特定的行业需要对日志的合规性有一定的要求,可以在开发的过程中按照合规性进行规范,以满足法规和安全标准。
通过以上的这些叙述,由此可见,在当下的云原生时代,可观察性、监控和日志分析不再是可有可无的选择,而是确保应用程序成功的不可或缺的一部分。
6. 后话
一个产品越到后期修复问题的代价就越大,这是每个作为测试人员都理解且经历过的道理。同样的在云原生的形态下,我们也需要理解即使有了那么多种类型的测试活动来保障产品的质量,最终用户层面仍然会碰到各种各样的问题。测试的目的是要降低那些意料之外的问题出现的机率,尽可能的提高产品的健壮性,协助产研团队完善各类质量保障的机制,哪怕是出了问题,也可以快速定位与修复,然后从中汲取教训,来继续优化下一个迭代产品版本。
当然质量保障从来不是测试一个团队的课题,它需要整个公司层面的参与与合作。在实际的项目中情况来看,受限于预算、生产力、时间表、交付周期、各种依赖服务、环境可用性等各种因素,是不可能用所有已知的测试策略彻底测试应用的情况比比皆是。所以,测试团队还需要采取基于风险的测试方法,还必须认识到,如果产线上实际用户遇到产品问题,就会有各种额外成本,比如测试成本、调试成本、机会成本、修复成本、验证成本和维护成本等。虽然云原生生态的各类实际特性更适合于当下的行业整体业务条件,但也不可轻视以上的各类风险,这些因素造成的印象往往正是各大企业与公司所无法忽视与承担的成本损失。总的来说掌握以上这些测试技术与策略并将新老方法进行结合正是当下各个测试团队与公司业务层所需要的,如此一来才可以在现今的行业中为客户提供更高质量的服务与产品。