《家国梦》游戏自动化测试

发表于:2019-9-29 17:58

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:Jiahonzheng    来源:掘金

  《家国梦》是最近很火的一款不用氪金的手游,在周围同学好友的怂恿下,我走上了“不归路”。这游戏玩法相当简单,就是拾取金币和搬运货物,攒足金币升级建筑。在这过程中,我们还可以学习国家当前政策。
  由于游戏玩法很简单,这让我萌发了自动化测试(开挂)的念头。
  项目地址:github.com/Jiahonzheng… 。
  演示视频:www.bilibili.com/video/av692… 。
  MuMu 模拟器
  我们使用网易游戏推出的 MuMu 模拟器,进行自动化测试。安装过程很简单的,这里也就不提了。这里的核心要点是 开启 USB 调试选项 和 adb 调试地址(127.0.0.1:7555)。
  BTW,由于我使用的手机是 SONY Xperia Z5 Premium ,故我将模拟器的分辨率设置为 1920*1080 ,项目所用到的素材也都是基于此分辨率制作的。
  UIAutomator2
  我们使用 UIAutomator2 作为自动化测试工具,其工作流程大致如下:
  在移动设备上安装 ATX 守护进程,其会启动 UIAutomator2 服务(默认端口:7912)进行监听。
  我们在PC上编写测试脚本,发送脚本至到移动设备的server端。
  移动设备通过 Wi-Fi 或 USB 接收到 PC 发送的脚本,执行制定的操作。
  我们执行下列命令完成 UIAutomator2 的安装和初始化工作(请务必确保已完成 adb 连接)。
   # 安装依赖
  python -m pip install uiautomator2
  # 安装 ATX 应用
  python -m uiautomator2 init
   在安装完 ATX 应用后,我们点击应用内部的**”启动 UIAutomator2“**,确保服务已开启。随后,我们编写并执行以下代码,即可生成屏幕快照。
   import uiautomator2 as u2
  d = u2.connect("127.0.0.1:7555")
  d.screenshot("Game.jpg")
  滑屏拾币
  在游戏中,每栋建筑都可产生一定数量的金币,我们可在建筑物间滑动,来拾取金币。为实现滑屏拾币的自动化,我们可调用 device.swipe 方法,这是 uiautomator2 提供的实现触摸滑动的函数,我们需要为其传入起始点屏幕坐标和终止点屏幕坐标。
  便于开发,我们为每块地建立对应的编号,具体如下图所示。
  编号与屏幕位置的对应关系如下。请注意,这是 1920*1080 尺寸下的屏幕位置。
   @staticmethod
  def _get_position(key):
  """
  获取指定建筑的屏幕位置。
  """
  positions = {
  1: (294, 1184),
  2: (551, 1061),
  3: (807, 961),
  4: (275, 935),
  5: (535, 810),
  6: (799, 687),
  7: (304, 681),
  8: (541, 568),
  9: (787, 447)
  }
  return positions.get(key)
   我们的滑屏拾币的策略很简单:分 3 次滑屏,第 1 次是 1 - 3 号建筑,第 2 次是 4 - 6 号建筑,第 3 次是 7 - 9 号建筑。
   def _swipe(self):
  """
  滑动屏幕,收割金币。
  """
  for i in range(3):
  # 横向滑动,共 3 次。
  sx, sy = self._get_position(i * 3 + 1)
  ex, ey = self._get_position(i * 3 + 3)
  self.d.swipe(sx, sy, ex, ey)
  OpenCV
  目测该游戏是使用 Unity 实现,我们在 weditor 里无法获取足够的 Hierarchy 信息,因此为了实现搬运货物的功能,我们只能选择图像识别的策略:我们获取游戏的屏幕快照,然后判断其中是否含有货物,若有则搬运至目的建筑。我们可以使用 OpenCV 的模版匹配功能实现此需求。
  首先,我们需要安装 OpenCV 依赖。
 python -m pip install opencv
  我们先对 cv2.matchTemplate 进行一次简单的测试,看它的效果如何。
   import cv2
  # 读取快照
  screen = cv2.imread('Game.jpg')
  # 读取货物图片
  template = cv2.imread('targets/Sofa.jpg')
  # 获取货物图片的长宽信息
  th, tw = template.shape[:2]
  # 调用 OpenCV 的模版匹配方法
  res = cv2.matchTemplate(screen, template, cv2.TM_SQDIFF_NORMED)
  min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
  # min_val 可用来判断是否检测到货物
  # 矩形左上角坐标
  tl = min_loc
  # 矩形右下角坐标
  br = (tl[0] + tw, tl[1] + th)
  cv2.rectangle(screen, tl, br, (0, 0, 255), 2)
  cv2.imwrite('Result.jpg', screen)
  执行上述代码,我们即可在快照中标记出 Sofa 的位置(红框圈住的物体),这表明此方法是可以 work 的。
   搬运货物
  我们封装了 UIMatcher 类,用于探测物体是否存在,并采取相应举动。我们根据 min_val 的值,我们来判断是否已检测到货物。
   # 阈值判断。
  if min_val > 0.15:
  return None
  我们在 _match_target 函数中,实现了搬运货物的功能。由于 OpenCV 的模版匹配也有“智障”的时候,我们采用了冗余搬运的方式。
   def _match_target(self, target: TargetType):
  """
  探测货物,并搬运货物。
  """
  # 获取当前屏幕快照
  screen = self.d.screenshot(format="opencv")
  # 由于 OpenCV 的模板匹配有时会智障,故我们探测次数实现冗余。
  counter = 6
  while counter != 0:
  counter = counter - 1
  # 使用 OpenCV 探测货物。
  result = UIMatcher.match(screen, target)
  # 若无探测到,终止对该货物的探测。
  # 实现冗余的原因:返回的货物屏幕位置与实际位置存在偏差,导致移动失效
  if result is None:
  break
  sx, sy = result
  # 获取货物目的地的屏幕位置。
  ex, ey = self._get_target_position(target)
  # 搬运货物。
  self.d.swipe(sx, sy, ex, ey)
  组装程序
  到这里,我们已经把两个核心功能(滑屏拾币 和 搬运货物)都实现了。现在,我们需要对其组装。我们的方式很简单粗暴,在 Automator 类的 start 方法中,我们在循环里,周而复始地进行搬运货物和滑屏拾币的任务。
   def start(self):
  """
  启动脚本,请确保已进入游戏页面。
  """
  while True:
  # 判断是否出现货物。
  for target in TargetType:
  self._match_target(target)
  # 简单粗暴的方式,处理 “XX之光” 的荣誉显示。
  # 当然,也可以使用图像探测的模式。
  self.d.click(550, 1650)
  # 滑动屏幕,收割金币。
  self._swipe()
   结语
  在这篇博客中,我们使用了 MuMu 模拟器、UIAutomator2 和 OpenCV 实现了《家国梦》游戏的自动化测试,解决了两个“核心“玩法的自动化模拟问题:滑屏拾币 和 搬运货物 。当然,我们的实现是存在很多可以改进的地方,如货物的探测算法,或许我们可以使用机器学习来解决这个 Object Detection 的问题,哈哈哈。
 
      本文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号