云IaaS测试系列一分布式存储测试实践3-自动化测试

自动化测试是指通过一些自动化测试工具或者框架把之前以人为驱动的测试行为转换为以机器执行的测试过程。自动化测试作为测试领域的先进生产力很大程度上提升了测试执行效率,自动化通常与持续集成和持续交付(CICD)一起使用,没有自动化的CICD就像没有灵魂的躯壳,它的好处毋庸置疑。自动化测试是贯穿于研发流程的每个阶段,而不只是在系统测试阶段,比如单元测试、接口测试、功能测试以及集成测试等都适用于自动化测试。

概述

自动化测试是指通过一些自动化测试工具或者框架把之前以人为驱动的测试行为转换为以机器执行的测试过程。自动化测试作为测试领域的先进生产力很大程度上提升了测试执行效率,自动化通常与持续集成和持续交付(CICD)一起使用,没有自动化的CICD就像没有灵魂的躯壳,它的好处毋庸置疑。自动化测试是贯穿于研发流程的每个阶段,而不只是在系统测试阶段,比如单元测试、接口测试、功能测试以及集成测试等都适用于自动化测试。

正确认识自动化

在开展自动化测试之前首先需要对自动化测试有一个正确的认知:

  1. 自动化测试主要是为了提升测试效率
    自动化测试是整个研发流程中的其中一环,它是以提升测试效率为目的;软件系统的质量防护需要通过构建完整的测试体系以及规范研发流程,在每个环节来保证。

  2. 自动化测试是随着产品的功能变化而变化,并不是一劳永逸的
    当产品功能发生变化后,也要对相应的自动化测试脚本进行修改适配,以适应新的功能;因此对于产品功能特性变化比较大且变化比较频繁的产品或者特性,并不适合做自动化测试,否则自动化测试脚本的维护成本会变高,反而影响测试效率

  3. 不是所有的功能测试都可以自动化
    产品变化大且频繁的的功能、带主观判断的测试(如UI用户体验、需要依靠经验判断的测试)、必须人工参与的功能、产品表现不明确的功能以及需要操作硬件的功能不适合做自动化。

  4. 自动化测试对产品的可测试性和可观测性有很大的要求
    自动化测试对产品的可测试性和可观察性有很大的要求,手工测试可以通过查询日志、gdb打桩等方式实现测试和观察系统表现,但是自动化不能,因为这种方式极不稳定(比如日志的随意修改会导致自动化失败),对自动化测试很不友好,需要产品能够提供相关接口或者工具来做自动化测试。

  5. 自动化测试也是需要成本的
    自动化测试需要长期维护、持续建设以及需要研发开发可测试和可观察性需求,因此开展自动化测试之前,需要考虑ROI(投入回报率)。比如某些功能只是临时性的需求,需要投入精力去建设自动化用例,但是实际的利用率并不高,因此该类功能的自动化测试需要综合评估。

  6. 自动化测试也需要设计
    自动化框架的选取和架构需要设计,自动化是一个长期持续的建设过程,越到后期越需要兼容更多的产品特性和需求,所以需要不断重构和优化自动化的架构设计。

  7. 自动化测试需要长期持续利用
    自动化测试应该结合CICD流程长期利用,用的越多,自动化测试的价值越大

自动化测试

自动化建设的首要任务是明确定义业务的用例集,比如建设产品基线用例库,然后根据用例集选择一个符合业务实际需求的自动化框架进行建设,基线用例库中需要明确包含哪些类型的测试,筛选出适合自动化以及自动化价值比较大的用例集,对于不适合做自动化的用例需要根据实际情况来定制化处理(如提可观测性需求给研发、手工测试);以CBS产品为例,CBS产品基线用例库主要有以下几种类型的测试用例:

  • 接口测试用例
  • 功能测试用例
  • 故障注入等可靠性测试用例
  • 压力/性能测试用例
  • 升降级等可服务性测试用例
  • 极端故障下的灾难测试用例
  • 规格测试用例
  • 探索性测试

自动化测试框架

不能盲目的选择已有的自动化测试框架,框架选取更多的考虑是否适合当前业务,这依赖于对自动化用例的技术和需求把控,比如框架是否能够支持用例和配置解耦、是否支持在用例中进行并发和随机操作、是否支持测试集以及是否支持数据驱动等。选定自动化框架以后,需要对业务的自动化架构利用一些设计方法进行设计,比如设计公共库和公共方法、根据面向对象的设计方法设计用例结构和lib库等。下面是一个CBS自动化的简化版的架构设计:

公共Lib库提供了一些测试用例中必须的公共操作,如盘/快照等相关操作、配置解析、故障注入类等,供测试用例中调用;测试环境以配置的方式由测试配置中指定并通过配置解析库解析后传入到测试用例使用,测试用例中分为前置、运行和后置步骤。

接口测试自动化

接口类测试自动化成本较低,所以比较适合做自动化测试,其主要是对接口的参数、功能以及返回值做覆盖。接口测试一般需要如下

  1. 数据准备:准备被测接口需要的依赖数据
  2. 入口覆盖:对接口的参数进行完整性覆盖,包括正常和异常参数
  3. 数据完整性校验:校验接口的返回/错误码以及一些DB中的数据
    相同接口的测试用例比较雷同,其本身的逻辑也相对简单,差别在于参数以及返回值的覆盖,比较适合用数据驱动的方式进行开发。如:

功能测试自动化

功能测试和接口测试有部分重叠,其带有一定的业务场景和业务逻辑关系,功能测试自动化主要分为两种情况:

  1. 如果产品的接口设计的较好,则大部分功能测试可以通过接口的组合调用来覆盖,那么该类功能的自动化成本也较低,比较适合进行自动化建设;
  2. 如果产品的接口设计的不完善,则接口的组合调用只能覆盖部分功能,更多的功能需要一些其他手段:比如通过ssh登录到服务器进行shell命令操作,查看日志或者通过gdb打桩进行测试,那么这类功能的自动化建设相对较复杂,且稳定率容易受到网络/机器等多方面的影响。

实际在IaaS层很多产品的功能测试都是第2种情况,不是简单的调用接口来覆盖,更多的是通过ssh登录到被测设备或者通过客户端给被测设备发送命令,然后通过特定的一些手段进行观测。一般来讲P0级别的用例(核心流程)基本可以通过调用接口来覆盖,但是非P0的用例测试手段和自动化手段都需要一些特别的方式来完成,其自动化成本也是因产品而异。以CBS为例,一个云盘迁移的功能用例如下:

该用例需要在迁移在pending状态时进行其他操作,实际在做自动化测试时,该pending状态很难捕捉到,需要使用打桩的方式进行,因此该类功能自动化成本较高。

故障注入测试自动化

故障注入类的测试也可以做自动化,自动化成本因故障注入的难度而不同,一般情况会只针对L0级别的故障用例进行自动化,且自动化运行时只能串行运行(避免影响其他用例),所以故障测试用例的自动化率相对较低。故障注入测试用例一般并不是A-B-C这种流程式的执行方式,更多的是并行执行方式,比如A流程执行过程中并行注入B故障。另外故障注入测试用例的观察手段更多的是依赖监控手段来进行,传统的流程式自动化开发方式很难实现,因此该类测试比较适合使用CFT或者混沌测试的方式进行自动化测试,适用于在测试阶段进行持续测试和长稳测试。

压力性能测试自动化

压力测试和性能测试会存在根据系统表现动态调整压力,并对系统的性能瓶颈进行分析和报表,测试过程中需要有一定的人工参与,一般都是半自动化状态,由手工测试和自动化测试结合进行。对于系统基准性能的测试,可以完全自动化。

可服务性测试自动化

可服务性测试主要是指类似升级/回退、卡件或者机器更换等方面的测试,在IaaS层的可服务性测试会有很多操作硬件设备的步骤,因此其自动化成本会非常高。一般这类测试的自动化主要聚焦于软件升级/回退的自动化建设,软件升级/回退的自动化对产品的升级回退能力有很大的诉求,比如升级回退流程固化的组件,其自动化成本较低,自动化率也相对较高;但是对于流程不固化的组件或者产品,其自动化维护成本将非常高,一般都不建议进行自动化测试。

兼容性测试自动化

兼容性测试主要是指对被测系统的周边依赖(如数据库、操作系统、服务器及其他依赖组件等)进行兼容性验证,验证其相关的功能无兼容性问题,其测试内容以及兼容性测试点与业务强相关,非常适合用自动化来提升兼容性测试的效率(因为分布式系统的兼容性组合非常多),测试的前提是需要依赖产研侧有一个明确的兼容性列表。常见的流程如下图:

兼容性验证需要强依赖于研发和产品团队提供的兼容性列表(兼容性需求),因此在开展兼容性测试之前,需要产研明确出产品的兼容性需求

硬件兼容性

对于CBS来讲,硬件兼容性主要是指机型(不同服务器搭配不同型号、数量、类型的硬盘以及CPU和内存的配置)的兼容性

数据库兼容性

对于CBS来讲,数据库都是用云CDB,因此此处的数据库兼容性主要是验证数据库版本的兼容性。

软件兼容性

变更兼容性测试

CBS作为分布式存储,集群节点数较多,升级变更并不是一次性变更所有节点,而是按照节点和地域分批灰度变更,因此升级过程中的版本兼容性是影响升级过程中服务稳定性的一个重大风险,变更测试跟具体的变更策略有关,以CBS存储系统为例,需要以不中断用户IO为目标进行变更,变更过程中以一定的业务压力(如40%-50%压力)为背景,依次变更三副本中的某一边,每次变更单边后进行业务恢复和P0自动化验证,观察变更对用户io的影响,如下图

操作系统兼容性

主要是指对被测系统所部署的操作系统进行兼容性验证

第三方组件兼容性

如前文所知,分布式系统由很多组件组成,因此需要验证被测组件与直接交互的其他组件的版本兼容性,已确保服务没有兼容性问题。

示例

组件A需要支持从版本A1~An共n个版本的升级,并有如下依赖:

  1. 组件B:需要兼容b个版本
  2. 组件C:需要兼容c个版本
  3. 数据库D:需要兼容d个版本
  4. 机型M:需要兼容m个机型
  5. 操作系统O:需要兼容o个机型
    因此,需要验证的兼容性组合最多有nbcdm*o个组合,组合非常多,实际测试过程中要覆盖所有的组合并不现实,因此,我们需要尽可能收敛每个影响兼容性的因子,最好的情况是每个依赖都只有1个版本,那只需要测一次兼容性即可。

规格测试自动化

规格测试主要是指对产品的外部和内部规格指标进行测试,比如一个母机上支持挂载云盘的最大规格数,该类测试比较适合做自动化测试。但是,规格测试对环境诉求极高,需要投入一定对资源设备成本,一般在测试环境很难开展全面的规格测试。在我们当前的产品测试中,对于有明确规格的并对资源要求相对可控的测试一般会进行规格测试,并且进行自动化建设,比如:

  1. 单仓库最大允许创建的云盘数量
  2. 单CVM最大允许挂载的云盘数量等

CFT测试自动化

CFT测试可以作为探索性测试的一个分支,比较适合利用自动化测试来开展,它并不是一个个非A即B的测试用例,而是由很多单一的原子用例并发或者随机调度组成的一套综合性的测试集合。CFT测试对自动化框架有很大的要求,需要框架能支持用例的并发性、随机性、调度的灵活性以及用例之间的数据交换等特性。

测试单元集包含每个最小粒度的测试行为,可以是单个测试用例,也可以是单个测试步骤,如正常的盘操作用例/运维变更步骤或者故障步骤,测试套中包含多个按多种调度维度分类的测试单元,如顺序调度分组的测试单元按照A-B-C这种顺序执行,随机调度分组的测试单元按照随机的方式选择测试单元执行,测试套内的多个分组并行执行,中间产生的数据或者比测依赖的数据通过缓存交换数据。通过这种方式可以尽可能的模拟多客户的真实操作,多个特性和故障及相关操作随机并发运行。

自动化测试的应用

自动化测试必须依托于DevOps研发流程来使用,否则自动化测试的价值就极其有限。前面讲了自动化按照测试维度分为接口/功能以及各种系统级自动化测试,每种类型的自动化应该在不同的研发阶段发挥不同的价值,以下是CBS自动化测试在研发流程的使用方式:

  1. 开发阶段:在开发阶段主要通过CI流水线的方式(无论是代码提交触发的开发流水线还是定时出发的日构建流水线)承载流水线的方式,能够持续通过自动化来反馈开发阶段的代码质量。一般建议日构建流水线可以跑全量的自动化测试。
  2. 提测阶段:在提测流程中,使用接口/功能以及P0级别的系统测试自动化作为提测的门禁,保障测试介入前提测产品的质量,避免因质量不合格导致的测试阻塞等影响测试效率的情况。
  3. 测试阶段:自动化测试在测试阶段的应用不止于回归测试,其应该贯穿于整个测试阶段进行持续测试
  4. 发布阶段:自动化测试在发布阶段主要作用是验证发布阶段的质量,需要能够快速反馈,一旦发布测试出错,需要及时回退。所以对发布测试用例的选取不仅要考虑功能的覆盖度,也要考虑自动化测试的执行时间。
  5. 现网运营阶段:这一阶段的自动化测试主要分为两类:拨测自动化和日常现网运营自动化,拨测自动化需要长期持续运行,一般跟发布阶段的自动化测试一致,主要是保证系统的核心能力不出问题,一但出错能够快速反馈;日常现网运营自动化一般是按需定时运行,内容主要覆盖功能和接口的P0用例。

自动化测试的挑战

自动化测试主要的挑战在于自动化用例的健壮性和自动化框架的扩展性,自动化用例运行难免会失败或出错,造成自动化测试失败的原因有很多,大概可以分为以下几类:

  1. 被测系统Bug:这部分失败是我们希望看到的,说明自动化测试拦截了bug,这才是自动化测试的价值
  2. 工具或被测环境的问题:这部分主要是指自动化工具和被测环境出了问题,如执行机负载过高、被测环境异常或者遗留脏数据等问题,我们应该尽量收敛该类问题,一旦出现该类问题,说明我们这次的自动化测试是无效的。
  3. 测试用例的问题:测试用例因为被测系统的行为出现了变化没有同步适配,或者自动化用例本身有bug导致,我们也应该尽量收敛该类问题。
  4. 第三方不可抗拒因素:比如机器下线、网络问题等问题,这部分我们基本无能为力,只能在实际运营过程中持续去优化自动化用例,来减少部分不可抗因素对自动化用例的影响。

自动化测试是一个长期持续的过程,需要持续的维稳并长期利用才能发挥其价值,罗马不是一天建起来的,自动化测试也不是一天能够稳定的,需要包容部分失败,只有长期使用,自动化才会越来越稳,越来越发挥其价值,这也是对研发和测试团队最大的挑战。

结语

自动化测试只是作为一种提升测试效率的测试工具,它并不是万能的,不能指望自动化测试能发现和拦截所有问题,它只是尽最大可能发现更多问题,更不能指望自动化测试替代人工测试,尤其是复杂的系统。我们要正确的认识自动化测试,合理的利用自动化测试。