デコシノニッキ

ホロレンジャーの戦いの記録

MRTK の Input Recording Service を使って自動テストする

先日リリースされたMRTKに,入力イベントの保存と再生をエディタ上でできる素敵サービスが追加されました。

microsoft.github.io

主な用途は,使い方の説明や予期しない動作検出,テストなどです。

  • Creating automated tests for interaction, manipulations, solvers, etc. Creating the movement of controllers and hands for these tests can be time consuming. Recording input directly can speed up the process and provide real-world data. See Writing tests using input animation
  • Teaching the use of UX elements through animations. Showing users how to interact with buttons and other objects can smooth the learning curve.
  • Debugging unexpected behavior that may be encountered during regular use. The recording system supports a "rolling buffer" concept that allows recording recent input in the background. See Input Recording Service.

MRTK ではなくとも,こういった機能は HoloLens 標準の機能として提供されてはいます。

docs.microsoft.com

ただまあ,実機が必要になるので使いにくい。ビルドメンドクサイ(本音)

テスト用シーンを作成する

「何をテストするか」について考えることは,テストを実施する上でとても重要です。が,今回はお遊びなので「ボタンを押すとキューブの色が赤色になる」ということを期待したテストを行います。

シーンは次のように構成しました。色を変える対象のCubeとイベント発火用のPressableButtonです。

f:id:haikage1755:20190908194929p:plain:w450

Pressable Button から,クリックしたときに赤色のMaterialに差し替えるよう画像のように設定しました。

f:id:haikage1755:20190908195151p:plain:w450

テストを書く

続いて,テストを作成していきます。まず,Test 用ディレクトリを作成します。

f:id:haikage1755:20190908195449p:plain:w450

生成したディレクトリ内にテストを作成します。

今回はMonoBehaviourTestを使います。使い方の詳細については,下記記事を参照してください。

blog.d-yama7.com

できあがったテストは以下の通りです。

using NUnit.Framework;
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.TestTools;

namespace Tests
{
    public class InteractionTest
    {
        /// <summary>
        /// あらかじめセットアップしたシーンを呼び出してテストする
        /// </summary>
        [SetUp]
        public void SetUp()
        {
            SceneManager.LoadScene("SampleTestScene", LoadSceneMode.Single);
        }

        [TearDown]
        public void TearDown()
        {
            SceneManager.UnloadSceneAsync("SampleTestScene");
        }

        /// <summary>
        /// テストしたいコンポーネントを継承し、IMonoBehaviourTestを実装したコンポーネントを用意する
        /// </summary>
        private class MonoBehaviour_TestScenario : MonoBehaviour, IMonoBehaviourTest
        {
            private Renderer cubeRenderer;

            public bool IsTestFinished { get; private set; }

            private void Start()
            {
                cubeRenderer = GameObject.Find("Cube").GetComponent<Renderer>();
            }

            private void Update()
            {
                // テストシナリオを書く
                // テストが終了したらIsTestFinishedをtrueにする
                if (cubeRenderer.material.color == Color.red)
                    IsTestFinished = true;

                // PlayModeテスト内のyield return(下記)が終了し、テスト成功と判定される
            }
        }

        [UnityTest]
        public IEnumerator ボタンを押すとCubeが赤くなる()
        {
            yield return new MonoBehaviourTest<MonoBehaviour_TestScenario>();
        }
    }
}

テストする

さて,できあがったテストでシーンをテストしてみましょう。
テストランナーには,下図のようにテストが追加されていると思います。

f:id:haikage1755:20190908203449p:plain:w450

ダブルクリックすると,シーンが再生されます。
この状態でボタンをクリックすると,Cubeが赤くなり,テストが成功したとみなされシーンが停止します。

f:id:haikage1755:20190908204938g:plain:w450

入力の保存と再生

というわけで無事テストが通りました!
といっても,結局こんなマニュアル操作を都度都度やりたくはないです。ここで,Input Recording Service を使って楽してみようと思います。

[!NOTE] スクリプトの修正 (2019/09/08時点)
現行のバージョンだと動かないので,下記を参考に2か所修正を行ってください。
PR出したので,次バージョンではマージされているといいなぁ。
FIX: Input Recording Service by tattichan · Pull Request #5905 · microsoft/MixedRealityToolkit-Unity · GitHub

先ほど作ったシーンを再生します。

f:id:haikage1755:20190908205450p:plain:w450

InputRecordingのウィンドウはシーン再生中のみにしか開けないので注意です。

f:id:haikage1755:20190908205839p:plain:w450

赤丸のレコーディングボタンを押すと,入力を記録してくれます。この状態でボタン入力を記録し,保存しましょう。

f:id:haikage1755:20190908210227p:plain:w450

シーンを停止して,再度再生し,Playbackから先ほどのアニメーションをロードし,再生してみましょう!

f:id:haikage1755:20190908210627g:plain:w450

保存した入力を自動再生して,テストさせる

ここまできたらあとはもうテストで自分でやっていたことの代わりを保存した入力にさせるだけです。

Start文のところで,PlaybackServiceを取得し,再生したいアニメーションを指定して再生します。

if (MixedRealityServiceRegistry.TryGetService(out IMixedRealityInputSystem inputSystem))
{
    var playbackService = (inputSystem as IMixedRealityDataProviderAccess).GetDataProvider<IMixedRealityInputPlaybackService>();
    playbackService.LoadInputAnimation(System.IO.Path.Combine(Application.dataPath, "ButtonPushAnimation.bin"));
    playbackService.Play();
}

あとはテストランナーからいつも通り実行するだけです!

f:id:haikage1755:20190908214023g:plain:w450

[デコシノニッキ]は、Amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、Amazonアソシエイト・プログラムの参加者です。」