浅谈游戏客户端自动化测试

正文

—————总该会点自动化了吧
 回想起来,自己入行游戏测试已有两年。

游戏的自动化测试一直是不少测试人员热衷于讨论的话题之一,但这种技术其实并不新鲜,无论是传统的互联网行业还是游戏行业,都会大量使用自动化测试技术。

简单聊聊自动化测试

—————先进行初步了解定义吧
什么是自动化测试

既然要做自动化,就得先知道什么是自动化。简单地说,就是把平时测试手工执行测试用例的过程,转为工具或者脚本来执行。

但其实,这并没有确切的定义, 笔者更加偏向认为这是个比较泛化的概念,只要使用了程序化的手段去完成测试的流程,就可以定义为自动化测试。

为什么要做自动化测试

既然自动化测试如此场景,那必然有其可取之处,笔者认为最突出的优点包括:

提升测试效率:常见的例子就是每日冒烟这种重复性极高的测试工作,或者兼容性测试这种步骤简单但重复工作量极大的工作。使用自动化测试可以释放这部分人力,让测试的哥们儿有更多时间深入的进行测试。

进行手工难以执行的极端测试:通常包括超长时间的客户端稳定性测试,或者概率测试。使用自动化脚本长时间保持客户端运行,确认客户端长时间运行的稳定性如何。概率测试简单地说就是超高数量级的抽卡,确认抽卡概率符合预期。

自动化测试方案

—————控件搜索or图像识别?

自动化的对象是游戏,而游戏通常的载体有:客户端、服务端、编辑器。而针对游戏客户端的自动化也是最常见到的,本文主要也是基于游戏客户端进行讨论。

主流的自动化思路有两种:一种是图形识别,另一种是控件操作。典型的例子就是网易的Airtest和腾讯的GAutomator。这里简单说下两者的特点。

图像识别

无入侵:作为测试人员,可能会没有权限得到项目源码然后使用编辑器打开,再嵌入你需要的SDK。而对游戏无入侵的图像识别变成了十分突出的优点。

效率较低:图像识别毕竟的步骤是截图和图像处理,这都是比较慢的步骤。想要识别游戏内出现时间较短的UI(如击杀提示等),就会十分不可靠。

维护较难:对于开发阶段的游戏,通常会存在大量临时UI。每次更新UI时都需要维护一次脚本,自然提高了维护成本。

图像识别:图像识别的最大优点是什么?那自然是可以识别图像(什么废话)。对于需要确认界面正确性,常见的方法是与一张预期内的界面截图作比较,而这通常是控件搜索方案难以实现的。

控件操作

高效率:对比图像识别方案,因为无需截图和图像处理,自然提高了许多效率。

较复杂:因为需要将相关SDK嵌入游戏中以获取游戏控件信息,所以部署起来自然是比图像识别麻烦的。

易于维护:通常只要和项目组的开发哥们儿约好,不要随意改控件的名称,维护起来就会简单许多。

在实现期间,图像识别、控件操作通常是互相结合的,这也是为什么Airtest会集成了POCO。通常来说如果测试有拿到项目的源码权限的话,优先考虑控件操作为主的方案,再辅以图像识别。如果没权限那就只能图像识别了。

具体实现

—————一点个人经验
笔者并没有主导过自动化工具的实现,这里就不误人子弟讨论推荐的自动化框架如何设计了,就说几个设计自己自动化项目时需要注意的点吧。
用例管理

初次尝试自动化的时候,用的是Airtest提供的IDE,回想起来用例管理和代码调试用那个IDE简直就是灾难,真不知道当时怎么坚持写下去还让别的同事跑起来的(?

通常,在用例设计的时候,不能出现一条用例引用另一条用例的情况,如果两条用例之间有重复的共性,可以把这一共性新建为一个方法。

以json为例,简单展示下笔者在json的测试用例模板:

				
					{
  "用例全局参数1": 1,
  "用例全局参数2": 2,
  "caseList": [
    {
      "index": 0,
      "name": "用例名称",
      "stepWaitTime": 5,
      "该条用例参数1": 1,
      "该条用例参数2": 2,
      "stepList": [
        {
          "index": 0,
          "stepName": "步骤名称",
          "该步骤参数1": 1,
          "该步骤参数1": 2
        },
        {
          "index": 1,
          "stepName": "步骤名2",
          ......
        }
      ]
    },
    {
      "index": 2,
      "name": "用例名称2",
      ......
    }
  ]
}

				
			
模块分层

OK,我们来回忆下大学那过时课本上学到的软件经典分层架构:表示层、数据访问层、业务逻辑层。分层有诸多好处:减少耦合、提高复用性、提高可维护性等。我们的测试脚本相对正式的大规模开发来说,减少很多因为每层边界带来的管理成本,同时一定程度上减少了因为多层调度带来的性能下降问题。

当然,做一套自动化并不需要完整参照这分层架构,我们可以鉴于分层的优点出发,尝试设计自己的分层模块。可能的分层如下:

框架底层

  • 测试框架源码:存放GAutomator、Aitrtest源码等
  • 其他基础组件:设备连接、设备操作、数据处理、报告输出等
  • 基础配置:主要包括运行时的配置管理、环境配置管理等

用例层

  • 用例库:存放用例的位置
  • 数据库:存放执行日志、测试结果相关的位置

业务层

  • 原测试框架中的接口无法满足需求时,进行二次开发、上层封装的内容
  • 仅适用于当前游戏项目的工具、SDK等内容
二次开发

GAutomator是一个相对轻量级的自动化测试框架,里面提供的接口并不多,通常需要进行二次开发。通常,若存在原有接口无法满足需求的情况,会进行二次开发,通常二次开发的主要目的,是为了方便用例编写时复用。

通常可以通过两种方式去进行抽象:

  • 玩家单个操作
  • 固化自动化流程

先说第一种:

比如说要针对游戏内的载具进行遍历的自动化测试,那必然每个载具都需要重复「上车」和「下车」的动作,那我们就可以抽象出这两个动作,进行二次开发,GAutomator的代码如下:

				
					TESTRESTPYE = Tuple[bool, str]

def go_aboard(device: Device) -> TESTRESTPYE:
    """上车"""
    engine = device.engine_connector()

    if isinstance(engine, GAutomator):
        engine: GAutomator

        // keyevent是GA中仅适用于PC或编辑器的模拟键盘映射方法
        // 游戏内按「F」上车
        ret = engine.keyevent(KeyCode.F)[0]
        print(f"上车结果:{ret}, {type(ret)}")
        if ret == RespStatus.SuccessJson.value:
            return True, "上车成功"

    return False, "上车失败"

				
			
然后是第二种,指的是已经固化的自动化流程,可以理解为每次冒烟都要重复跑的新手流程。固化的自动化流程是以第一类单个操作为基础搭建而成的。还是接上,要对游戏内所有载具进行遍历,每辆载具需要进行的操作是相同的,这样我们遍历一个载具所需要的所有流程是固化的,由此可以抽象成一个方法,伪代码如下:
				
					TESTRESTPYE = Tuple[bool, str]

def car_check(device: Device, car_location: list) -> TESTRESTPYE:
    // 传送至车辆隔壁,执行成功标记step为True
    step = move_to_the_car(device: Device, car_location)
    if step:
        // 上车
        step = go_aboard(device: Device)
    if step:
        // 驾驶车辆
        step = move_forward(device: Device)
    if step:
        // 下车
        step = go_aboard(device: Device)
    if step:
        return True, "车辆遍历通过"
    return False, "车辆遍历不通过"   

				
			
二次开发抽象出来的方法与用例不同,通常可以互相引用,但也要注意抽象的细致程度(颗粒度)以及模块划分的问题,好的二次开发会极大方便用例编写与整个自动化项目的维护。

结语

—————继续加油吧!
回想起笔者第一次做的自动化项目当时业务经验缺乏技术能力不足前辈指导也没有项目组支持可以说当时做出来东西是一个差不多DEMO规模的,虽然说这个东西比较刚需算是落地了但是增加了不少学习维护成本
 
现在,原因终究是自己确实是太小瞧了自动化测试工作缺乏东西太多也没有比较好的理论基础支撑自己实现自动化期间的决策选择

这篇文章写的东西还是比较浅自动化测试技术很多东西没有提及到像是自动化流程稳定性保障监控前置环境准备输出测试报告可视化操作......

无论如何保持技术积累必须的这也是本文想要传达主要观点技术技术能力会束缚你的测试思想,同样也会拓宽你的测试思想了解更多技术之后才会知道自己能用什么样技术组织自己的测试策略或者说已有测试策略上能做怎样补充

guest
0 评论
内联反馈
查看所有评论