PlayModeでUnity Test Toolsを使ってみた
はじめに
Unityでテストを書くのに使用するUnity Test Tools。
Unity5.3から組み込みとなり、AssetStoreで別途インストールする必要はなくなりました。
ただ、CoroutineやTween系(iTweenやDOTweenとか)は確認することができず、別の方法でテストを行う必要がありました。
が、5.6から強化され、PlayModeでテストを行うことができるようになりました。
ということで今回は、PlayModeでDOTweenを使って3Dモデルを移動させるコードをテストしてみることにしました。
準備
前述の通り、Unity Test Toolsを使うのに何かをインストールする必要はありません。
ただし、デフォルトではPlayModeでのテスト実行が無効になっているため、
これを有効にします。
- メニューの Window > Test Runner からTest Runnerウインドウを開く
- PlayMode タブを開き、 Enable playmode tests をクリックして有効にする
- UnityEditorを再起動する
あとは PlayMode タブの Create PlayMode test または右クリック > Create > Testing > PlayMode Test C# Script からテスト用クラスを追加します。
(※PlayMode用のファイルは、Editorフォルダ内に入れてしまうとPlayMode用のTest Scriptと認識されないようなので、
それ以外の場所に保存する必要があります)
テスト対象のコード
テスト対象のコードは、下記の関数 Move とします。
ObjectController.cs
using DG.Tweening; using UnityEngine; public class ObjectController : MonoBehaviour { public GameObject EventHandleObject; protected ObjectCtrlEventHandler ObjectEventHandler; public Tweener Move(GameObject targetObject, Vector3 goalPosition, float duration, Ease easeType) { return targetObject.transform.DOMove(goalPosition, duration) .SetEase(easeType) .OnComplete(ObjectEventHandler.OnFinished); } private void Awake() { ObjectEventHandler = EventHandleObject.GetComponent(); } }
ObjectCtrlEventHandler.cs
using UnityEngine; public class ObjectCtrlEventHandler : MonoBehaviour { public void OnFinished() { Debug.Log("Finished"); } }
- 引数として渡しているGameObject(targetObject)を、goalPositionの位置までduration秒で移動させる、という内容です。
- 移動が完了したら ObjectCtrlEventHandler > OnFinished が呼ばれます。
テストを書く
この関数に対するテストを書きます。
ObjectControllerTest.cs
using System.Collections; using DG.Tweening; using NUnit.Framework; using UnityEngine; using UnityEngine.TestTools; namespace Tests { public class ObjectControllerTest: ObjectController { private GameObject targetObject; [SetUp] public void Init() { // 初期化処理. JUnitでいう@Before. EventHandleObject = new GameObject(); ObjectEventHandler = EventHandleObject.AddComponent(); targetObject = new GameObject(); } [Test] public void ObjectControllerTestSimplePasses() { // 待ち時間が不要な処理はTestを使う. } [UnityTest] public IEnumerator MoveIn0Sec() { var tween = Move(targetObject, Vector3.one, 0f, Ease.Flash); // Tweenerを返す場合OnCompleteの処理をダミーに置き換えることができる. tween.OnComplete(() => Debug.Log("")); // 結果が戻るのが次フレーム以降のため、少し待つ. yield return new WaitForSeconds(0.1f); Assert.AreEqual(targetObject.transform.position, Vector3.one); } [TearDown] public void Dispose() { // 終了処理. JUnitでいう@After. } } }
Testの実行
上記のようなTest Scriptを作成すると、Test Runnerウィンドウ > PlayModeタブ に該当のTestが表示されます。
あとは「Run All」や「Run Selected」をクリックすればテストが実行されます。
NUnit
- テストコードは、NUnit(ver.2.6.4)がベースになっており、初期化処理([SetUp])、終了処理([TearDown])が使用できます。
初期化処理
- テスト対象である ObjectController のAwakeでGetComponentしている ObjectCtrlEventHandler は、
Testでは(GameObjectにアタッチができないため)NullReferenceExceptionになるので SetUp で値をセットしています。
DOTweenの処理が反映されるタイミング
- DOTweenで処理を行う場合、durationを0にしていても同フレーム内では座標値の変更が反映されないため、 WaitForSeconds で待ち時間を設けます。
- [Test] では戻り値がvoidに限定されるため、 [UnityTest] を使って戻り値を IEnumerator にし、yield return new WaitForSeconds を使用しています。
おわりに
これまで以上にテスト可能な箇所が増えたことで、ぐんとテストが書きやすくなったように思います。
一点気になっているのは、例えばJenkinsなどのCIツールを利用する場合にも、今回のテストは実行できるのか?ということです。
こちらについては近いうちに試してみたいと思います。
参照
- Unity Test Runner - Unity - Manual ※2017.5.27現在英語版と日本語版でバージョンが異なるため注意
- Unity-Technologies / UnityTestTools — Bitbucket
- Unity5.3からUnit Tests Runnerが組み込みになった - Qiita
- 実践 JUnit