购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

4.3 基于架构的测试策略

不同软件架构在本质上决定了软件逻辑结构的复杂性,在深层次决定了软件可靠性等质量特性。不同软件架构决定了测试设计层次的选择及静态分析、逻辑测试、可移植性测试、可扩展性测试的方法选择,与测试环境搭建密切相关。软件测试策略制定的重要方法之一就是基于架构引导,对于不同软件架构,应有针对性地进行测试策划,制定测试策略。

4.3.1 分层架构

分层架构(Layered Architecture)将软件系统划分为若干水平层,每一层都具有清晰的角色定义和分工,各层之间通过接口实现通信和交互。图4-10给出了一个常见四层结构的分层架构。

表现层用于实现用户界面,负责视觉和用户交互;业务层用于实现系统业务逻辑;持久层提供相应的数据,其中,SQL语句就放在这一层;数据库层用于保存数据。用户请求将依次通过这四层的处理,不能跳过任何一层。可以在业务层和持久层之间,增加一个服务层,为不同业务逻辑提供通用接口。分层架构用户请求流程如图4-11所示。

在分层架构的每一层,按照独立原则或敏捷原则,独立地进行逻辑覆盖、功能覆盖和业务覆盖,并对系统建模,封装浏览器控制、结果解析逻辑等,为每一层提供一个接口,实现系统测试。一旦系统功能、环境发生变化,或代码调整时,需要对系统进行重新部署。当用户请求大量增加时,须依次对每一层进行扩展,但受每一层内部耦合关系制约,扩展困难。分层架构测试一般遵循单向逐层调用,针对接口编程、依赖倒置、单一职责及开放封闭的策略。

图4-10 常见四层结构的分层架构

图4-11 分层架构用户请求流程

对于单向逐层调用,如果将 N 层架构各层自底向上依次编号为1,2,⋯, N ,当被测架构第 层只能依赖第 k −1层,而不依赖其他层时,也就是说如果 P 层依赖 Q 层,则 P 的编号一定大于 Q 的编写。该策略保证了依赖的逐层性及其整个架构的依赖逐层向下,不能跨层依赖,从而保证了依赖的单向性,即只能上层依赖底层,底层不能反过来依赖上层。

编程接口是一种抽象的、在语义层面具有接合作用的语义体,而非具体的语言元素,具体实现可能是接口,抑或是抽象类,甚至可能是具体类。在软件测试过程中,将接口定义为两种形式:一种是一定领域中行为的约定,即接口实现必须遵循的指定契约;另一种是在一定维度上,同类事物的共同抽象,针对不同维度,同类事物具有不同展现形式。

针对接口编程原则,如果约定将 N 层架构各层自底向上依次编号为1,2,⋯, N ,则第 层不依赖具体的第 k −1层,而是依赖第 k −1层的接口,即在第 k 层中不应该有第 k −1层中的具体类,第 k 层的编程仅仅针对第 k −1层的接口进行。

依赖倒置是一种重要的软件设计思想,即不能让高层组件依赖低层组件,不论是高层组件还是低层组件,均依赖抽象。该原则定义具体依赖,而上面所定义的则是抽象依赖。具体依赖指如果 P 层中有一个及以上的地方实例化了 Q 层中某个具体类,则称 P 层具体依赖 Q 层。

抽象依赖指如果 P 层没有实例化 Q 层中的具体类,而是在一个及以上的地方实例化了 Q 层中的某个接口,则称 P 层抽象依赖 Q 层,也称接口依赖 Q 层。依赖倒置针对接口编程,而不是针对实现编程,依赖抽象而非具体实现。

4.3.2 事件驱动架构

事件驱动架构(Event-driven Architecture)是通过事件通信的分布式异步软件架构,由事件队列、事件分发器、事件通道、事件处理器四部分构成。事件队列是接收事件的入口,事件分发器负责将不同事件分发到不同业务逻辑单元,事件通道是事件分发器与事件处理器之间的连接渠道,事件处理器实现业务逻辑,处理完成后发出事件,触发下一步操作。事件驱动架构涉及异步编程,需要考虑远程通信、失去响应等情况,涉及多个处理器,很难回滚,难以支持原子性操作。事件驱动架构如图4-12所示。

图4-12 事件驱动架构

虽然独立的单元测试并无特别之处,也不存在特别的困难,但需要特殊的测试客户端或测试工具来生成事件。事件驱动架构的分布式和异步特性导致基于这类架构的软件系统测试较其他架构系统困难。

4.3.3 微服务架构

微服务架构(Microservices Architecture)是将单体应用拆分为多个能够独立构建、独立测试、独立部署、独立管理的服务,通过轻量级通信机制交互的分布式、松耦合、自治且相互解耦的软件架构,较好地解决了基于单体应用,使用单一技术栈导致系统资源利用率低、错误隔离性差、不易扩展、难以支持持续交付等问题。微服务架构如图4-13所示。

微服务架构具有三种实现模式:一是RESTful API模式,由API提供服务,云服务即属于这一类模式;二是RESTful应用模式,由网络协议或应用协议提供服务;三是集中消息模式,采用消息代理,实现消息队列、负载均衡、统一日志和异常处理,这种模式可能导致单点失效,通常以集群方式实现。

对于微服务架构,软件系统将单一可部署单元拆分为多个服务,具有良好的可测试性、延展性和可部署性。微服务架构强调服务的独立性和低耦合性,因服务被拆分得过小,服务、模块及层次之间存在复杂的依赖关系,导致整体性能下降。若单独测试某个服务或服务中的某个模块,就必须剥离其对其他微服务的依赖关系。集成不同服务的端到端测试往往会因为一个服务的变更而发生错误,对多个服务的UI端到端测试即E2E测试,必须采取一定的防干扰、防误报策略。通用Utility类就是典型例子。其解决方案就是以冗余换取架构的简单性,即将它们复制到另一个服务中,通过Mock等方式来实现。与此同时,微服务架构的分布式特征使其难以实现原子性操作,交易回滚困难,且不同服务可能在不同环境或配置下运行,尤其是一些后端服务,与前端服务的运行环境可能截然不同,面临着诸如基础环境准备、配置管理、服务间依赖关系复杂,以及服务监控、鉴权、安全控制等困难。若考虑对每种服务设立自动化管线时,就必须有针对性地设置相应的环境配置。因此,需要一个能够提供基础环境且具备服务发布、服务治理、运行监控等功能的PaaS平台支撑。

图4-13 微服务架构

微服务相对轻量,适宜部署于轻量的容器平台。微服务生命周期过程是DevSecOps微服务开发及基于容器平台部署、测试、管理、运营微服务的过程。因此,不仅需要对微服务功能、性能、部署、协同能力等进行测试,而且需要基于容器平台,采用DevSecOps流程组织实施微服务测试。在微服务开发阶段,完成单元测试后的微服务镜像进入测试环境镜像仓库,自动完成镜像扫描,扫描通过的镜像可部署于测试环境,根据规则构建微服务测试域,生成测试用例,驱动测试。在关联项目管理工具Jira中创建缺陷跟踪记录,并从Jira发送邮件给相关人员,开发人员修复缺陷提交代码自动编译,完成单元测试,打包到镜像仓库,然后部署于测试环境,启动新的测试流程,形成一个测试闭环。

基于微服务架构的测试结果取决于网络系统的稳定性,尤其是涉及数据存储及外部通信时,如测试过程中不能摆脱这些因素的影响,则可能得到随机性误报,干扰测试结果。微服务架构测试应力求为服务内部每个模块的完整性及每个模块之间、各个服务之间的交互,提供全面的测试覆盖,同时保持测试的轻便和快捷。较基于整体式架构的测试,微服务架构对测试提出了新的挑战。为应对新挑战,微服务架构测试策略应基于自动化、层次化和可视化三个基本原则。所谓自动化,就是随着测试任务的持续增加,将测试策略聚焦于测试自动化。自动化测试必须足够稳健、稳定,不能动辄误报,否则反而导致居高不下的维护成本。所谓层次化,就是采用层次化的测试方法,将测试自底向上划分为单元测试、服务测试和UI测试三个层次,粒度由细到粗,范围由小到大。所谓可视化,就是将构建、测试、部署等相关任务构建在一个流水线上,使得所有测试结果可视化。工程上,基于微服务生命周期过程模型,将微服务架构测试划分为持续集成、测试环境测试、生产环境验证三个阶段。

4.3.3.1 持续集成

代码提交会触发自动构建流程,完成代码检查、代码编译、单元测试、打包、构建镜像并上传镜像到镜像仓库等过程。这一阶段,代码检查及单元测试是保证微服务代码质量的重要措施。需要强调的是,需要从不同侧面、不同层次测试功能的容错性,制定测试策略时,必须清醒地认识到,把握验证错误的测试设计更为重要。

4.3.3.2 测试环境测试

基于DevSecOps,测试所需基础设施由云平台提供,测试人员直接从云平台申请资源,构建测试域。微服务可能需要其他微服务协同支持,或使用测试挡板程序模拟协同微服务,以构建测试环境。

1.构建测试域

使用标准API隔离底层服务版本的逻辑变化,只要接口不变或相互兼容,就认为是同一个API,而不兼容的变更则认为是一个新接口;部署业已开发完成的API或暂时使用API挡板,保证测试过程平滑推进;对于公共组件,使用基线版本,构建最小测试域,完成功能、接口及单一功能的性能测试。

2.部署及功能测试

功能测试旨在验证微服务及基于微服务架构的应用系统是否满足功能性要求。根据需求和设计规则生成测试用例,验证输入和输出是否符合预期结果,以及微服务部署、配置、安全等能力。这一过程是DevSecOps自动化流程的一部分,流程定义应满足特定的场景要求,这正是测试策略中必须明确的问题。

3.API接口测试

微服务会在API网关上映射API接口,使用API网关有助于服务治理。一个微服务可能会映射为多个API,或多个微服务映射为一个API,同时定义API接口的访问控制、流量控制、安全、路由等策略。API接口配置难以实现自动化,需要接口管理人员来完成相应工作,然后生成测试用例,完成接口测试。

4.应用测试

基于微服务架构的集成测试,可以看作应用测试。基于微服务架构,根据业务需求,将应用编排部署为不同的业务应用,如客户中心应用、产品中心应用、服务中心应用等。应用测试通常包含界面测试、业务流程测试、部署扩展测试等。

5.性能及非功能性测试

制定微服务架构测试策略时,需要充分考虑微服务性能、可用性、容错性、弹性及容灾备份能力等测试验证。工程上,可以基于容器的弹性伸缩、资源调度及高可用部署等特性,验证微服务的高可用性、弹性、容错性及容灾备份能力,而微服务性能测试需要考虑基准测试、负载测试、压力测试、容量测试等,以验证微服务在不同条件下性能指标的达标情况。

4.3.3.3 生产环境验证

微服务部署于生产环境之后,需要基于最终生产环境进行测试验证。通常采用验收测试或灰度发布机制,使用历史数据或模拟数据,验证业务逻辑的正确性。对于验收测试,需要明确验收条件,包括功能性和非功能性验收条件,如平均延迟时间、单实例负载支持、资源需求等性能要求。通常,验收测试需要用户参与,开展基于用户体验及交付能力的验证。

多版本情况下,特别是类似于App服务,可能经常发生变更,需要在生产环境中导入部分流量进行验证。引流方式多种多样,可以根据需要导入不同请求进行验证。这也正是我们在API层实现负载均衡和API治理的原因之一。

4.3.4 云架构

云架构(Cloud Architecture)是指将构建云所需组件及功能连接起来,提供应用运行的在线平台。通常,云架构包括处理单元和虚拟中间件两部分。处理单元实现业务逻辑,虚拟中间件负责通信、保持Sessions、数据复制、分布式处理和处理单元部署等任务。虚拟中间件包含消息中间件、数据中间件、处理中间件、部署中间件四个组件。云架构如图4-14所示。

云架构的高负载、高扩展、动态部署特点,使得基于云架构的软件测试变得非常困难,必须研究开发基于云架构的测试技术及测试策略。第一,构建安全测试评价指标体系和综合可信性评估模型,研究制定运营公正和透明性测试方案;第二,创新云测试服务模式,通过云测试平台,为用户提供测试服务,对测试请求信息进行存储,供虚拟机测试调用,根据用户请求规模,通过交互平台进行虚拟机配置和调度,在云端进行测试验证;第三,性能测试是指验证云计算在各种负载条件下的服务性能,基于不同测试场景,模拟云计算的极限测试和压力测试;第四,进行云测试时,必须保证云平台的安全,验证云是否安全的一个有效方法是有选择地在公共云上暴露数据,然后查找可能存在的各类风险和缺陷;第五,通过云计算模型,建立云计算质量模型与安全模型,应用测试数据对基于云架构应用系统进行质量与安全性评价。

图4-14 云架构 9lGmshyi+hMVxH+QO+EwYg/H4mOSCi71uyfCjyPCIRgpHvCWbMSYOO7X2jYCY3Z4

点击中间区域
呼出菜单
上一章
目录
下一章
×