興味の源泉

自分が興味を起こせるようなネタを雑多に書き綴るブログ

【Unity】TestRunnerのPlayModeでテストする

一つ前の記事でTestRunnerをEditorModeで実行してテストする方法を書きました。
じゃあPlayModeは?ということでPlayModeもやっていきます。

実は前回のEditorModeは参照周りがよくわかっておらず、そこを棚上げしてEditorフォルダに入れることにより「ビルドに入らないからええやろ」としていた部分があります。

今回はちゃんとそこもやっていきます。

※注意:Unity2017.3で入った機能を使っているため、それ以前のバージョンではその部分は参考にならないかもしれません(AssemblyDefinitionというファイルです)


まず、TestRunnerのダイアログを起動しPlayModeタブを押して表示します。
f:id:nanami_yamato:20190324200119p:plain

Projectでテストフォルダを作りたい任意のフォルダに移動します。
そこでTestRunnerの「Create PlayMode Test Assembly Folder」ボタンをクリックしてテストフォルダを作成します。
フォルダとその中に「フォルダ名.asmdef」というファイルができています。
このファイルにテストの設定を行っていきます。
f:id:nanami_yamato:20190324210935p:plain


まずは設定せずにどういう挙動になるのか見ていきます。

テストのフォルダ以外の任意の場所に EasyGameObject クラスを作ります。
内容はGameObjectの位置を移動、移動前の位置を保存取得できるようにするだけのクラスです。

using UnityEngine;

public class EasyGameObject : MonoBehaviour
{
    // ひとつ前のPositionを保持
    private Vector3 beforePosition = Vector3.zero;

    void Start()
    {
        SaveBeforePosition();
    }

    // ひとつ前のPositionの変数に現在位置を保存
    public void SaveBeforePosition()
    {
        beforePosition = this.transform.position;
    }

    // beforePositionの取得
    public Vector3 GetBeforePosition()
    {
        return beforePosition;
    }

    // 位置を移動させる
    public void MovePosition(Vector3 nextPosition)
    {
        SaveBeforePosition();

        this.transform.position = nextPosition;
    }
}


ではこのEasyGameObjectをテスト側のコードで使おうとしてみます。

テストのフォルダで右クリック > Create > Testing > C# Test Scriptで作ります。
ファイル名はEasyGameObjectTestとしました。

PlayModeではコルーチンで実行することができます。
[UnityTest]を関数の上に書き、戻り値はIEnumerator です。

まずはテストが通ることを確認したいので実装なしで作ります。

using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;

namespace Tests
{
    public class EasyGameObjectTest
    {
       [UnityTest]
        public IEnumerator EasyGameObjectTest1()
        {
            yield return null;
        }
    }
}


「RunAll」または「RunSelected」で実行すると当然テストが成功します。
ではこのコードにEasyGameObjectのテストを追加していきましょう。

しかし、EasyGameObjectを記述しても見つからないと言われます。
これはテストの参照が設定されてないため起こっている現象です。

なのでフォルダを作るときに一緒にできた「フォルダ名.asmdef」に設定していきます。

その前に参照される側にも同じファイルが必要なので作ります。
EasyGameObjectの置いてあるフォルダで右クリック > Create > Assembly Definitionでasmdefファイルが作成されます。
f:id:nanami_yamato:20190324212139p:plain

テスト側のasmdefファイルを選択して「Assembly Definition References」にEasyGameObjectの置いてあるフォルダのasmdefファイルを設定します。
右の「+」を押して追加された行の右のボタンを押しダイアログから設定します。
f:id:nanami_yamato:20190324212213p:plain


これでEasyGameObjectTestでEasyGameObjectを使えるようになっています。

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

namespace Tests
{
    public class EasyGameObjectTest
    {
        private EasyGameObject easyGameObject = null;

        // 各テスト実行前にそれぞれ実行される
        [SetUp]
        public void SetUp()
        {
            Debug.Log("SetUp");
            GameObject obj = new GameObject("test");
            easyGameObject = obj.AddComponent<EasyGameObject>();
        }

        // 位置を設定して移動前の位置と現在の位置をログ出力
        public void MovePositionTestSetPosition(float x, float y, float z)
        {
            // 位置設定
            easyGameObject.MovePosition(new Vector3(x, y, z));

            // 移動前の位置をログ出力
            Debug.Log("before_pos : " + easyGameObject.GetBeforePosition().ToString());
            // 位置設定後のログ出力
            Debug.Log("after_pos : " + easyGameObject.transform.position.ToString());
        }

        [UnityTest]
        public IEnumerator EasyGameObjectMovePositionTest1()
        {
            Debug.Log("------------------------------------");
            MovePositionTestSetPosition(100f, 0f, 0f);

            Debug.Log("------------------------------------");
            MovePositionTestSetPosition(0f, 100f, 0f);

            yield return null;
        }

        [UnityTest]
        public IEnumerator EasyGameObjectMovePositionTest2()
        {
            Debug.Log("------------------------------------");
            MovePositionTestSetPosition(150f, 200f, 10f);

            yield return new WaitForSeconds(1f);

            Debug.Log("------------------------------------");
            MovePositionTestSetPosition(700f, -1000f, 150f);

            yield return null;
        }
    }
}


一気にテストコード書きましたが、やってる内容は位置を移動させその前後の座標を出力しています。
2つ目のテストでは1回目と2回目の出力に1秒待ち時間を入れています。
それにより、実行時間が1秒ほど伸びています。
実行時間は結果の関数名の横に出ています。

EasyGameObjectMovePositionTest1
f:id:nanami_yamato:20190324215112p:plain

EasyGameObjectMovePositionTest2
f:id:nanami_yamato:20190324215123p:plain


TestRunnerのPlayModeを使ってみましたが、なかなか使い勝手が良さそうです。

ただEditModeでテストできるものはEditModeでやったほうが速いです。
とはいえ、まずはテストできるようにしていくことが大事なので使えるプロジェクトでは必ず使っていきます。
できるところから少しずつ。



環境
2019/03/24時点、Unity2018.3.9f1を使用

参照
Unity Test Runner - Unity マニュアル
スクリプトのコンパイルとアセンブリ定義ファイル - Unity マニュアル