AirtestとPocoとOpenSTFによるUnity製スマートフォン向けゲームの実機自動テスト環境構築とその利用方法

 AirtestとPocoとOpenSTFによるUnity製スマートフォン向けゲームの実機自動テスト環境構築とその利用方法

「CEDEC 2020」の発表資料です。
http://cedec.cesa.or.jp/2020/session/detail/s5e82a55322244

Ec2fcdc4ea7905b289967a2c4c43e154?s=128

CyberAgent SGE Engineer

September 04, 2020
Tweet

Transcript

  1. AirtestとPocoとOpenSTFに よるUnity製スマートフォン向け ゲームの実機自動テスト 環境構築とその利用方法 CEDEC2020 株式会社サムザップ 三森裕史

  2. 今回の話の概要 ・実機で自動テストをしよう!端末は手元になくてもOK ・「テスト」がないのですぐにできるテストを構築したい ・非プログラマーでも自動化したい ・コロナ禍であってもだれもが同じ端末でチェックできたら良いよね ・甘口セッションです Python知らなくても大丈夫 Androidの話が殆どですが、iOS周りの動向も補足します 2

  3. 自己紹介 携帯電話やスマートフォンの上で動くゲームを作る人 最近はテストやツール周り等 2017年サムザップ入社 CTO室所属 三森 裕史 過去の発表等 builderscon2018 3

  4. 株式会社サムザップ  2009年5月 CyberAgent子会社として設立 事業内容  スマートフォンゲームの企画、配信、運営 会社概要 4

  5. 戦国炎舞 -KIZNA- 2013年4月サービス開始 戦国時代を舞台にしたカードゲーム 運営開始から7年が経過  検証項目の増大が課題 5

  6. この仕組みを導入すると何ができるか 実機連打テストの自動化! 6

  7. この仕組みを導入すると何ができるか CSVファイル等を利用しノンプログラマでも自動テストが作れる仕組み 7

  8. 新規タイトルでの運用 ゲームを遊び続けて、エラーが出力された際にSlackへ通知 コンポーネントの中身の値チェック 指定された箇所の動画、スクショ撮影、保存 8

  9. 今回使用するツールの紹介と説明 9 Airtest Poco DeviceFarmer (OpenSTF)

  10. Airtestについて https://airtest.netease.com/ ・NetEase社が開発した画像認識によるテストコードを記述できる環境 とライ ブラリ群 ・IDEによって気軽にテストコードが記述できる ・テストコードはPythonのコードとして保存され、Jenkinsのような各 種CI環 境で実行することが可能 10

  11. Airtestについて 11

  12. Airtestでできること ・Pythonによるテストコードを記述できる  主に画像認識ベースの処理 ・タッチ、スワイプ等の処理  切り抜いた画像でテンプレートマッチングし、合致した箇所にタップ ・各種assert  画面内に切り抜いた画像と一致する箇所があるか? 12

  13. Airtestでできること 13

  14. Pocoについて Airtestのライブラリ Unityや各種ゲームフレームワークの UI情報を取得し、Python上で操作 することができる。 14

  15. Pocoでできること Unityや各種ゲームフレームワークのUI情報を取得 15

  16. DeviceFarmerについて 16 同一ネットワーク下でブラウザごしに実機を操作できるプロダクト 元々はCyberAgent社で開発していた端末管理のOSS 現在はOpenSTFからDeviceFarmerというプロジェクトに名称変更 Web上から端末の操作(APKインストールやWebブラウザ操作、 エクスプローラー等)が可能 →

  17. DeviceFarmerについて 17

  18. DeviceFarmer 端末リスト 18

  19. DeviceFarmer 端末画面 19

  20. 余談:CyberAgentでは 沖縄に設置されており、ネットワーク越しに 各子会社が利用できるようになっています 20

  21. じゃあ、それらを組み合わせると? ステイホームしながら、指定の端末でテストができる 21

  22. 導入方法から、テスト作成まで 22

  23. 導入方法 Airtest IDEのインストール https://airtest.netease.com/ 23

  24. IDE画面 24

  25. 導入方法 Unity側にPocoSDKを導入 https://github.com/AirtestProject/Poco-SDK 1.ライブラリのダウンロード 2.使用しているUIに合わせてファイルを削除 3.Unityのプロジェクトに導入 4.PocoManagerをScene上に設置する 25

  26. PocoSDK プロジェクトが利用するGUIシステム にあわせて、ファイルの除去を行う 26

  27. PocoSDK プロジェクトがuGUIを採用していたら NGUI,fairyguiを削除してUnityへインポート 27

  28. PocoManager 導入 #if ENABLE_AIRTEST // Airtestデバッグの為に実体化 var pocoGameObject = new

    GameObject(); pocoGameObject.name = "Poco"; pocoGameObject.gameObject.AddComponent<Poco Manager>(); #endif シーン上に予めPocoManagerを 配置しても動作するが、 シンボルで切り分けた方が 取り回しが良い 28
  29. Device Farmer の導入 node.js環境か、docker-component環境で構 成してる情報の方が多く、手間も少ないのでおす すめ 時間の都合上割愛しますがDocker環境を整え て、docker-composeファイルを用意し $ docker-compose

    up 資料末の参考資料に参考にさせ て頂いて、実際に起動させた docker-composeの参照先を記 載しております 29
  30. 起動画面 30 いきなりログイン画面を要求されますが適当でOK セキュリティを担保したい場合の処理は後述

  31. 準備中から進まない? ・ログを確認しよう ・起動させる前にUSB接続済み? ・https://github.com/openstf/stf/issues/407 ・https://github.com/openstf/stf/issues/670 導入時インストールされるstf.apk周りの動作チェック    stfアプリをadbで起動させる等の対処法あり 31

  32. ワークフロー 開発者はPocoSDK をUnityアプリに組み込む 32 Pocoが組み込まれた APKを出力

  33. ワークフロー テスト製作者はDeviceFarmer にアクセスし、端末を確保 33 APKをインストール 端末一覧から端末をクリックす ると「使用状態」になり 他の人が使えないように

  34. ワークフロー AirtestIDEを利用して UI情報を取得 34 adb connect した端末は自分 の手元にある端末と同様に あつかえる 誰でも実行可能なように

    Gitリポジトリに格納。
  35. ワークフロー 35 作成したテストはPythonコード として、Jenkins等の実行環境 へ Jenkins側はテスト実行時に DeviceFarmerから端末を確保 し、テストを実行する 新規バイナリか、テストコードの 更新がある度に実行する

    結果をSlack等に通知
  36. テストコードを書く from airtest.core.api import start_app from poco.drivers.unity3d import UnityPoco #

    ゲームを起動し、Pythonコードを実行すると # ゲーム内PocoSDKとPythonが接続される。 poco = UnityPoco() # 特定のゲームオブジェクトのタップ poco("BattleButton").click # 長押し処理 poco.long_click(pos=[0, 0], duration=3.0) # テキスト情報の取得 text = poco("ErrorCode").get_text() 36
  37. 取得できる情報 # UIの名前の取得 poco("CoalitionName").get_name() # UIの座標取得 poco("CoalitionName").get_position() # テキスト値の取得 poco("CoalitionName").get_text()

    # 体力を確認して、その値が0以下じゃなければ # みたいな処理をよく書いたりする hp = poco("HitPoint").get_text() if hp not 0: 37
  38. 38 エラーがあったら Slackに通知 def exists_end_report(self, poco): if poco("ErrorCode").exists(): image =

    poco.snapshot() text = poco("ErrorCode").get_text() self.messenger.upload("screen." + image[1], text, base64.b64decode(image[0])) sys.exit() 画面上にエラーコードが発行さ れていたらslackに投稿する
  39. 39 指定のスキルが見つ かるまで遷移   def skill_table_pos_check(self, skill_name): pos = self.poco(text=skill_name).get_position() #

    画面外に押したいボタンがある while pos[0] < 0 or pos[0] > 1: # スワイプさせたり、ボタンを押したり等の処理 if pos[0] < 0: self.poco("LeftArrowButtonSprite").click() if pos[0] > 1: self.poco("RightArrowButtonSprite").click() pos = self.poco(text=skill_name).get_position()
  40. 40 動画撮影 poco.device.start_recording() # test.mp4で動画ファイルを出力 poco.device.stop_recording(output="test.mp4") # 中断させる場合はis_interrupted=True poco.device.stop_recording(is_interrupted=True)

  41. 「自動化」に向けてもうひと工夫 41

  42. Python環境側 ・Airtest内で完結するなら .air ・Pythonコードとして動作させるなら .py Pythonの各種ライブラリの取り回しを よくしたいのであればpure pythonで 構築するのがおすすめ 42

  43. DeviceFarmerとAirtestの連携 端末画面から、リモートデバッグコマンドをコピペして利用する。 これも自動化したい。 43

  44. Device Farmer 端末の確保 Device FarmerはOpenAPI対応なので好みの言語でClientを生成する ・https://github.com/swagger-api/swagger-codegen もしくはJenkinsのプラグインを利用する ・https://plugins.jenkins.io/open-stf 44

  45. 端末確保の自動化 def main(adb_path, serials): api_instance = create_api_instance() devices = api_instance.get_user_devices()

    print(devices) for serial in serials: print(serial) device = swagger_client.AddUserDevicePayload(serial) add_user_device(api_instance, device) thread = api_instance.remote_connect_user_device_by_serial(serial, async_req=True) res = thread.get() remote_connect_url = res.remote_connect_url cmd = adb_path + " connect " + remote_connect_url while True: proc = subprocess.run(cmd, shell=True, stdout=PIPE, stderr=PIPE, text=True) time.sleep(1) if 'connected' in proc.stdout: break swagger-codegenを利用し て、Pythonでクライアントを作 成 45
  46. ツール利用と組み合わせのまとめ Pocoを組み込み、Airtestでテストを作成、DeviceFarmer環境でテストを行う ・結果はSlackやスプレッドシートに送信  あまりUnitTestのような感覚はなくE2Eで正しく動くか?が大きい ・recording機能で動画を保存できるようにしておく エビデンスとして 46

  47. UI名を利用したテストの利点 デザインが変わってもPocoは「PlayButton」 で位置情報を取得できる PlayButton 47 Poco(“PlayButton”).click()

  48. テストを作成するチームと開発チームを分離できる テストを作る側は開発チームのコードとは独立したテストコードを作成できる  チームの分離が可能 48 C#知らなくても テストが作れる テスト製作者に 配慮せず設計変更

  49. 使用事例 49

  50. 要件 戦国炎舞はGVGのゲーム トップ層はシビアな戦いを行っている バージョンの差異等でレスポンスの悪化があると 非常によろしくない とはいえ、毎回人間がレスポンスを確認するのは… ということで 50

  51. Airtestを利用して、高速連打し続ける 30分間攻撃し続けて、バージョン毎の攻撃数に差異がないか? 51

  52. CSVで行動を作れるようにする。   特定ルールでのスキル効果チェック 52

  53. CSVを利用したテストの作成 53 デバッグ用APIで各種データ調整 対戦相手の設定、ルール等 ログをスプレットシートに記述 端末を操作して自動実行させる API_XXX.py API_XXX.py

  54. 自動化のタスクを CSVで表現する task_classes = [TaskHttpGet, AttacklTask, TacticsTask, HealTask, SpecialTask, CheerTask,

    TaskBasicTap, TaskScreenShot, TaskHttpRuleChange, TaskHttpBattleBegin, TaskHttpBattleEnd, TaskHttpEditStatus, TaskStartWar, TaskGameStart, SpreadSheetLogger, TaskHttpEditHp, TaskTriggerCheck] obj_graph = pinject.new_object_graph(binding_specs=[PocoCSVBindingSpec()]) for task in task_classes: instance = obj_graph.provide(task) self.worker[instance.tag()] = instance for index, row in df.iterrows(): if row[0] in self.worker.keys(): var = self.worker[row[0]].action(row) 大まかに表現するとこのような 感じ タスク毎にクラスを作成し、 CSVのコード毎に呼び出す 54
  55. CSVを利用したテストの作成 例えば: ・テスト環境を構築するAPI ・「合戦」中に掛かる、倍率のリセット ・実際に端末を操作してテスト内容を実行するコマンド 端末操作とAPI操作を1つのファイルから命令できるので 手順ミス等がなくなる 55

  56. Tips おまけ等 56

  57. DeviceFarmerのユーザー認証 CyberAgentでは「同一ネットワークのみ&LDAP認証」で運用 https://github.com/openstf/stf/issues/47 LDAP認証ってどうやるの? https://blog.cybozu.io/entry/2018/12/20/110000 サイボウズさんの事例 57

  58. 高速化のちょっと したコツ poco("UI名").click() が微妙に遅い… 内部の「touch_method」 によって手法が変わる #Before poco = UnityPoco()

    poco("LeftBgSprite").click() 58
  59. 高速化のちょっと したコツ dev = device() poco = UnityPoco() screen_width, screen_height

    = poco.get_screen_size() pos_attack_scale_x, pos_attack_scale_y = poco("LeftBgSprite").get_position() pos_x = screen_width * pos_attack_scale_x dev.minitouch.touch((pos_x, pos_y)) https://github.com/DeviceFarmer/minitouch 59
  60. 起動時にUSBで接続済みのデバイスに モジュールがインストールされる 接続しているAndroid端末に必要なモジュールがインストールされる  minicap デバイスキャプチャツール ・https://github.com/openstf/minicap   ・スクリーンショットの高速なやり取りに利用する  minitouch android内のinputファイルを書き換えるツール ・https://github.com/DeviceFarmer/minitouch

      ・高速にタッチする処理等に利用 60
  61. minitouch,minicapは元々OpenSTFの プロジェクト 個別に公開されていたものが、Airtestで利用されているOSSとして公開したも のが別のプロジェクトで利用されOSSを公開した会社でそのプロジェクトを利用 する。という面白い構図。 61

  62. DeviceFarmerのiOS周り issueは上がっていて、プルリクエスト用のプロジェクトも進んでいる。 自分でXcode周りのビルドができるのであれば試すことはできそう。 間に合えば資料アップロード時にここらへんの資料を追加します。 62

  63. AirtestとiOS :ちょっとまだ非推奨 (スピードが遅い…) https://airtest.doc.io.netease.com/en/tutorial/6_IOS_automated_t esting/ を参考に https://github.com/AirtestProject/iOS-Tagent ↑をXcodeでビルドして、端末にインストール Mac上でhomebrewを導入し、brew install usbmuxd

    iproxy 8100 8100で接続 63
  64. Pocoを拡張する Pocoは、GameObject内の Componentを取得して内部の 値を返すという動きをしている ライブラリを拡張すれば独自の Componentの特定の値を 取ってこれる 64

  65. ADBを「合わせる」 ADBのバージョンをあわせないと、AirtestやCLIで実行する際にADBを kill-server start-serverを繰り返すことになるので対応したい PIPとAirtestの中のadbをあわせるのにリンクを作成しておくとよい 65

  66. DeviceFarmerを自力で用意するのが大変 https://www.headspin.io/ headspinさんのような サービスを利用するのも 一つの手段 66

  67. まとめ 1.実機による自動テストが可能になることで、安定稼働とチームの安心感向上 に寄与することができる 2.プロジェクト外からテストによる貢献ができるので開発リソースの柔軟な投入 が可能プロジェクト側にも負担をかけない 3.Pythonの知識が多少要求されるが、十分習得可能な範囲と考えられ、非プ ログラマーでも自動のテストが構築できる 67

  68. まとめ アイディアと今後の開発でさらに有効活用できると考えておりますので、みなさ んと一緒にいろいろ考えていけたら良いなと思っております。 68

  69. 参考文献や素材等 かわいいフリー素材集 いらすとや 4,750,000+ free and premium vector icons in

    SVG, PNG, CSH and AI format. Azusa 3 - 大体いい感じになる無料 Keynote・Googleスライドテンプレート 【Unity】「Airtest IDE」を使用して Android のゲームで画像認識による UI の自動テストを試してみた Androidのリモート操作/管理ツール「OpenSTF」をDocker for Windowsで使う OpenSTF+Dockerで社内Android端末管理システムを Mac上に構築する https://airtest.netease.com/ AirtestProject/Poco-SDK Device Farmer stfのiosサポート https://github.com/tmobile/stf_ios_support Welcome to Poco (ポコ) documentation! — poco 1.0 documentation 69