Unity上でオブジェクトベースのモンキーテストを実行できる Monkey Test Helper パッケージ*1の v0.15.0 では、いくつか破壊的変更が入りました*2。 そのマイグレーションについて解説します。
Monkey Test Helper は、オートパイロットフレームワーク Anjin の UGUIMonkeyAgent の内部実装にも使われています。Monkey Test Helper v0.15.0 は、Anjin v1.9 で反映予定です。
なお Monkey クラスおよび Anjin をカスタマイズなしで使用しているプロジェクトには、本変更の影響はありません。
IOperator.OperateAsync() のシグネチャ変更
まず、第一引数の型、つまり操作対象の指定が Component から GameObject に変更されました。
この変更は実際のマウスやタッチ操作と合わせるためで、1つのGameObjectにイベントを受けられるコンポーネントが複数あるとき、そのすべてにイベントが飛びます。
また、第二引数として RaycastResult を受け取るようになりました。
これは Camera からのレイキャストで返される先頭(最前面)の RaycastResult で、クリック座標などを含みます。
RaycastResult は、後述の IReachableStrategy および GameObjectFinder の戻り値として取得できます。
オペレータの実装によっては使用しませんし(たとえば UGUITextInputOperator)、ゲームタイトル側で EventData の中身を参照しないのであれば default で構いません。
この変更により、たとえば『Anjin非公式ファンブック』7.4.2で紹介している RandomClickOperator のようなカスタムオペレーターにおいて、レイキャストを通した座標を引き継いでクリックできるようになります。
IOperator.OperateAsync() にログおよびスクリーンショット出力の責務が移動
v0.14 までは呼び出し元(たとえば Monkey クラス)がログおよびスクリーンショットの出力を担っていましたが、
v0.15.0 以降はオペレーターの責務となります。
この変更は、将来の機能追加への布石です。 ドラッグ操作などのオペレーターや、操作座標をGameViewにオーバーレイしてスクショに収めることを想定しています。
なお、この変更に伴ない OperateAsync() の引数に ILogger と ScreenshotOptions が追加されています。
IsIgnored() および IsReachable() がインスタンスメソッド化
モンキーテストで無視するオブジェクトを判断する IsIgnored() とオブジェクトがユーザー操作可能かを判断する IsReachable() が、static 関数からインスタンスメソッドに変更されました。
それぞれ、IIgnoreStrategy.IsIgnored() と IReachableStrategy.IsReachable() になります。
デフォルト実装も提供されています。
この変更により、各ストラテジは状態を持てるようになります。
IReachableStrategy および GameObjectFinder のシグネチャ変更
IReachableStrategy.IsReachable() が、out パラメータで RaycastResult を返すようになりました。
また GameObjectFinder の FindByNameAsync() および FindByPathAsync() メソッドの戻り値の型が GameObject から GameObjectFinderResult に変更されました。
GameObjectFinderResult は、GameObject と RaycastResult を保持する struct です。
この変更によって得られるようになった RaycastResult は、前述 IOperator.OperateAsync() の第二引数に渡されることを想定しています。
コード例
v0.14以前
var finder = new GameObjectFinder(); var buttonObject = await finder.FindByNameAsync("StartButton", reachable: true, interactable: true); var buttonComponent = buttonObject.GetComponent<Button>(); var clickOperator = buttonComponent.SelectOperators<IClickOperator>(_operators).First(); // ここでスクリーンショット撮影・ログ出力(呼び出し側の責務) await clickOperator.OperateAsync(buttonComponent);
v0.15.0以降
var finder = new GameObjectFinder(); var result = await finder.FindByNameAsync("StartButton", reachable: true, interactable: true); var buttonObject = result.GameObject; var clickOperator = buttonObject.SelectOperators<IClickOperator>(_operators).First(); await clickOperator.OperateAsync(buttonObject, result.RaycastResult);