前回は、Unity の Test Framework パッケージにより作られたテスト用モジュール内のスクリプトから、自作スクリプトを参照できるようにするために、自作スクリプト群を自作モジュールに分け、そのアセンブリ定義ファイルの参照をテスト用モジュールのアセンブリ定義ファイルに追加しました。
これで自作スクリプトの名前空間や関数をテスト用モジュールのスクリプトから利用できるようになりました。
今回は、自作スクリプトのテストコードを作成して具体例として紹介します。
※ Unity は 2021.3.14f1、Test Framework パッケージは Version 1.1.33、Visual Studio は Community 版 Version 17.2.5、 OS は Windows 10 です。
テストコードの作成
テスト対象は自作スクリプトの SCTilemapExtensions.cs に定義された関数群です。
タイルマップに関する関数です。
そのため、テスト時には前回紹介したようにタイルマップのプレハブを用います。
テスト関数の名前は
- Unity Test Runner でのテストの作成と実行 – Unity マニュアル
- C# 単体テスト チュートリアル – Visual Studio (Windows) | Microsoft Learn
では、英語を _ で区切っているようです。
英語は難しいので、「対象クラス名_対象メソッド名_通し番号」の形式で関数名をつけます。
SCGetTileCount 関数
Tilemap コンポーネントに配置されているマップチップの総数を得る関数です。
テストでは、マップチップの個数が 0 個のときに 0 を返すか、 3 個のときに 3 を返すか、確認します。
Tilemap コンポーネントを持つゲームオブジェクトをプレハブとしてテスト用に用意しました。
※他の方法として、テスト関数の中で Tilemap を作成して、任意の個数だけマップチップを配置する方法もあると思いますが、複雑になるとテスト用の処理自体にバグが発生しやすくなると思い、前述の方法を選びました。
- マップチップが 0 個配置されているタイルマップ
- マップチップが 3 個配置されているタイルマップ
タイルの作成については次のページにも書いてあります。
- Unity の Weighted Random Tile を作ってみる | Compota-Soft-Press
- KoalaDungeon のサンプルのパレットでタイルマップの編集(2) | Compota-Soft-Press
これらのテスト用プレハブをテスト関数で読み込み、 Tilemap コンポーネントを対象の関数に渡し、戻り値が答えとあっているかを確認するコードを書きます。
using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using UnityEngine.Tilemaps;
using SakuraCrowd.SCTilemap;
public class TestSCTilemapExtensions
{
/// <summary>
/// Resorces フォルダ内からプレハブを読み込み、それをインスタンス化し、Tilemap コンポーネントを得ます。
/// </summary>
/// <param name="tilemapPrefabPath">プレハブの Resources の後のパスです。</param>
/// <param name="go">受け取るゲームオブジェクトです。 null の場合はログ出力と Assert が発生します。</param>
/// <param name="tilemap">受け取る go の持つ Tilemap コンポーネントです。 null の場合はログ出力と Assert が発生します。</param>
public void InstantiateTilmeapFromPrefab(string tilemapPrefabPath, out GameObject go, out Tilemap tilemap)
{
// プレハブを Resources フォルダ内から読み込みます。
GameObject prefab = Resources.Load(tilemapPrefabPath) as GameObject;
if (prefab == null)
{
Debug.Log("prefab is null. filepath = " + tilemapPrefabPath);
}
Assert.That(prefab, Is.Not.Null);
// プレハブをインスタンス化します。
go = GameObject.Instantiate(prefab);
if (go == null)
{
Debug.Log("go is null");
}
Assert.That(go, Is.Not.Null);
// Tilemap コンポーネントを取得します。
tilemap = go.GetComponent<Tilemap>();
if (tilemap == null)
{
Debug.Log("_wallsTilemap is null");
}
Assert.That(tilemap, Is.Not.Null);
}
/// <summary>
/// SCTilemapExtensions の SCGetTileCount 関数のテストです。
/// tilemapPrefabPath の Tilemap を SCGetTileCount 関数の結果と constraint が一致するか調べます。
/// </summary>
/// <param name="tilemapPrefabPath">テストに用いる Tilemap が含まれたプレハブの Resources の後のパスです。</param>
/// <param name="constraint"></param>
[TestCase("Test/Tilemap/TilemapCount0", 0)]
[TestCase("Test/Tilemap/TilemapCount3", 3)]
public void SCTilemapExtensions_SCGetTileCount_1(string tilemapPrefabPath, int constraint)
{
GameObject go;
Tilemap tilemap;
InstantiateTilmeapFromPrefab(tilemapPrefabPath, out go, out tilemap);
int actual = tilemap.SCGetTileCount();
Debug.Log("actual = " + actual + ", constraint = " + constraint);
Assert.That(actual, Is.EqualTo(constraint));
}
}
Test Runner から呼び出されるテスト用の関数は 52 行目の SCTilemapExtensions_SCGetTileCount_1 関数です。
関数の引数は、その前の 2 行の TestCase の引数と対応しています。
第 1 引数 tilemapPrefabPath はテストで用いる Tilemap を持つプレハブのパスです。
第 2 引数 constraint は、答えの数です。この場合は Tilemap に配置されたマップチップの個数です。
テスト関数で良く用いられる変数名に actual と answer/constraint があるようです。
テスト対象から得られた値は actual (実際の値)、答えは answer や constraint(制約、期待する状態) を用います。
テスト関数の処理は TestCase が 2 つあるので、それぞれの引数が渡されて 2 回このテスト関数は呼び出されます。
処理の内容は以下です。
- InstantiateTilmeapFromPrefab 関数でお題のタイルマップをプレハブからインスタンス化します。
- テスト対象の SCGetTileCount 関数を呼び出し、検証する値を取得します。
- 引数で渡された答えの値と一致するか Assert の中で確認します。もしも一致しなければテストは不合格になります。
メニュー [Window]→[General]→[Test Runner] で Test Runner ウィンドウを表示し、2 つの TestCase または上位のテスト関数名をダブルクリックしてテストします。
テストが行われ、結果が表示されました。緑のチェックマークがつけば合格です。
SetUp などの属性について
今回は使いませんでしたが、便利そうなテスト用の属性もたくさんあります。
その一部を紹介します。
SetUp 属性は、その関数をテスト関数が呼ばれる直前に毎回呼び出されるイベント関数にします。
毎回テストの最初に行う処理があれば SetUp 属性を指定した関数に実装すると良いでしょう。
OneTimeSetUp 属性は、その関数を最初のテストの直前に一度だけ呼び出されるイベント関数にします。
テストごとには行わない、初期化処理などを実装すると良いでしょう。
Values 属性は引数の前に指定し、その引数の値を複数指定できます。
TestCase で引数を渡す場合と似ていますが、複数の引数に Values を指定するとそのすべての組み合わせでテスト関数が呼び出されます。
【Unity】Unity Test Runner(Test Framework)で複数の入力値を取り扱う方法まとめ – LIGHT11
まとめ
今回は、Unity の Tilemap を利用する自作スクリプトの関数を Test Framework でテストしました。
テスト用のタイルマップは、シーンで任意の数マップチップを配置したプレハブを用意しました。
テスト用の答えは、その Tilemap のプレハブのパスと対応させて TestCase 属性の引数で渡しました。
今回とは異なるテストの手順を使うことがあれば、今後も紹介していきたいです。
参照サイト Thank You!
- Unity のリアルタイム開発プラットフォーム | 3D/2D、VR/AR のエンジン
- Test Framework – Unity マニュアル
- Unity Test Runner でのテストの作成と実行 – Unity マニュアル
- C# 単体テスト チュートリアル – Visual Studio (Windows) | Microsoft Learn
- NUnitのAssert.ThatメソッドにIsとかHasとかを入れて柔軟なテストコードを書こう – Qiita
- [Unity] C#クラス(スクリプト)のテスト方法 | ソフトライム
- 【Unity】Unity Test Runner(Test Framework)で複数の入力値を取り扱う方法まとめ – LIGHT11
コメント