ゲーム開発では、手動テストはすぐに繰り返しになり、エラーが発生しやすくなります。新しい機能の開発やバグの修正に取り組む際に、終わりのないテスト サイクルに陥ったことはありませんか?
コード テストを自動化することで、コードの追加、削除、変更によってプロジェクトが中断されないことを保証する反復的な (ただし重要な) QA タスクに費やす時間を減らし、クリエイティブなゲーム開発に費やす時間を増やすことができます。
Unity は 、Unity Test Frameworkを使用して、ゲームの自動テストを作成、管理、実行するのに役立ちます。
Unity Test Framework (UTF) を使用すると、 編集モード と 再生 モードの両方でプロジェクト コードをテストできます。スタンドアロン、iOS、Android などのさまざまなプラットフォームのテスト コードをターゲットにすることもできます。
UTF は、 パッケージ マネージャーを使用してプロジェクトに追加することでインストールされます。
内部的には、UTF は .NET 言語用の有名なオープンソース テスト ライブラリである NUnitと統合されています。
UTF で記述できるテストには、編集モードと再生モードという 2 つの主なカテゴリがあります。
編集モードのテストは Unity エディターで実行され、エディターとゲーム コードの両方にアクセスできます。つまり、カスタム エディター拡張機能をテストしたり、テストを使用してエディターの設定を変更し、再生モードに入ることができます。これは、インスペクターの値を調整してから、さまざまな設定で自動テストを実行する場合に便利です。
プレイ モードテストを使用すると、実行時にゲーム コードを実行できます。テストは通常、[UnityTest]属性を使用してコルーチンとして実行されます。これにより、複数のフレームにわたって実行できるコードをテストできます。デフォルトでは、プレイ モード テストはエディターで実行されますが、さまざまなターゲット プラットフォーム用のスタンドアロン プレーヤー ビルドで実行することもできます。
この例に従うには、Unity Asset Store から Starter Assets – Third Person Character Controller パッケージ をインストールし、新しいプロジェクトにインポートする必要があります。
ウィンドウ > パッケージ マネージャーから UTF をインストールします。パッケージ マネージャーの Unity レジストリで Test Framework を検索します。必ずバージョン 1.3.3 (執筆時点での最新バージョン) を選択してください。
UTF がインストールされたら、テキスト エディターで Packages/manifest.json ファイルを開き、次のように依存関係の後に testables セクションを追加します。
、
"testables": [
"com.unity.inputsystem"
]に同意します
ファイルを保存します。これは、後でプレイヤー入力をテストおよびエミュレートするために Unity.InputSystem.TestFramework アセンブリを参照する必要があるときに役立ちます。
エディターに戻り、新しいバージョンをインストールします。
[ウィンドウ] > [一般] > [テスト ランナー] をクリックして、 テスト ランナー エディター ウィンドウを表示します。
チュートリアルのこの部分では、再生モード テストの作成に重点を置きます。テスト ランナー ウィンドウの [テスト アセンブリ フォルダーの作成] オプションを使用するのではなく、プロジェクト ウィンドウを使用して作成します。
プロジェクト アセット フォルダーのルートをハイライト表示した状態で右クリックし、[作成] > [テスト] > [テスト アセンブリ フォルダー]を選択します。
Tests.asmdef(アセンブリ定義) ファイルを含む Tests プロジェクト フォルダーが追加されます。これは、テストがゲーム モジュールと依存関係を参照するために必要です。
キャラクター コントローラー コードはテストで参照され、アセンブリ定義も必要になります。次に、モジュール間のテストを容易にするために、いくつかのアセンブリ定義と参照を設定します。
Assets/StarterAssets/InputSystem プロジェクト フォルダーを右クリックし、[作成] > [アセンブリ定義]を選択します。StarterAssetsInputSystemなど、わかりやすい名前を付けます。
新しい StarterAssetsInputSystem.asmdef ファイルを選択し、インスペクターを使用して Unity.InputSystemへのアセンブリ定義参照を追加します。「適用」をクリックします。
Assets/StarterAssets/ThirdPersonController/Scripts プロジェクト フォルダーを右クリックし、[作成] > [アセンブリ定義]を選択します。たとえば ThirdPersonControllerMainのように、わかりやすい名前を付けます。
前のアセンブリ定義と同様に、インスペクターで ThirdPersonControllerMain を開き、次の参照を選択します。
- Unity.InputSystem
- StarterAssetsInputSystem
「適用」をクリックします。
入力システムの一部をエミュレートするには、テストでそれを参照する必要があります。さらに、Third Person Controller コード用に作成するアセンブリで StarterAssets 名前空間を参照する必要があります。
インスペクターで Tests.asmdef を開き、次のアセンブリ定義への参照を追加します。
- UnityEngine.TestRunner
- UnityEditor.TestRunner
- Unity.InputSystem
- Unity.InputSystem.TestFramework
- ThirdPersonControllerMain
「適用」をクリックします。
最初のテストでは、Third Person Controller パッケージからメイン キャラクターをロードして移動することに関する基本事項について説明します。
まず、シンプルなテスト環境シーンと、作業に使用するキャラクターのプレハブ リソースを使用して新しいプロジェクトを設定します。
Assets/StarterAssets/ThirdPersonController/Scenes/Playground.unity という名前のシーンを開き、[ファイル] > [名前を付けて保存] メニュー を使用して、そのコピーを次の新しいパスに保存します。アセット/シーン/SimpleTesting.unity
ゲーム ビューにピンク色のマテリアルが表示されている場合は、レンダー パイプライン コンバーターを使用して、組み込みレンダー パイプラインからユニバーサル レンダー パイプライン (URP) にマテリアルをアップグレードします。簡単な概要については、この記事を参照してください。
プロジェクト アセット フォルダーに Resourcesという新しいフォルダーを作成します。注:ここで、UnityResources.Load() メソッドを使用できるようにするために、フォルダー名「Resources」が重要になります。
シーン ビューの PlayerArmatureGameObject を新しい Resources フォルダーにドラッグ アンド ドロップし、プロンプトが表示されたら Original Prefab の作成を選択します。プレハブアセットの名前を Characterに変更します。
これは、今後のテストで使用されるベース キャラクター プレハブになります。
新しい SimpleTesting シーンから PlayerArmature GameObject を削除し、シーンへの変更を保存します。
初期テスト設定の最後の手順として、[ファイル] > [ビルド設定]に移動し、[開いているシーンの追加] を選択して、Scenes/SimpleTesting シーンをビルド設定に追加します。
プロジェクト アセット フォルダー内のテスト フォルダーを選択します。右クリックして、[作成]>[テスト]>[C# テスト スクリプト]を選択します。
新しいスクリプトに CharacterTestsという名前を付けます。詳しく調べるには、IDE でスクリプトを開いてください。
初期クラス ファイルには、テストの基本を示す 2 つのメソッド スタブが付属しています。
次に、テストが「テストに重点を置いた」ゲームシーンを読み込むことを確認します。これは、重点を置いているシステムまたはコンポーネントをテストするために必要な最小限のものを含むシーンである必要があります。
CharacterTests クラスを更新して 2 つの新しい using ステートメントを追加し、InputTestFixture クラスを実装します。
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;
パブリッククラス CharacterTests :InputTestFixture
CharacterTests クラスの先頭に 2 つのプライベート フィールドを追加します。
GameObject の文字 = Resources.Load<GameObject>("Character");
キーボード キーボード;
キャラクター フィールドには、リソース フォルダーから読み込まれたキャラクター プレハブへの参照が格納されます。Keyboard は 、InputSystem によって提供されるキーボード入力デバイスへの参照を保持します。
CharacterTests クラスに独自のメソッドを用意して、基本 InputTestFixture クラスの Setup() メソッドをオーバーライドします。
パブリックオーバーライドvoidセットアップ()
{
SceneManager.LoadScene("Scenes/SimpleTesting");
base.Setup();
keyboard = InputSystem.AddDevice<Keyboard>();
var mouse = InputSystem.AddDevice<Mouse>();
Press(mouse.rightButton);
Release(mouse.rightButton);;
}
Setup() メソッドは、基本クラスの Setup() メソッドを実行し、テスト シーンをロードしてキーボード入力デバイスを初期化することで、独自の CharacterTests クラスを設定します。
マウス入力は、サードパーソン コントローラーがシミュレートされた/仮想キーボード デバイスからの入力を受け取り始めるためだけに追加されます。これは、ほぼ「フォーカスを設定する」アクションのようなものです。
最初のテストでは、プレハブからキャラクターをインスタンス化し、それが null ではないことを確認します。テスト クラスに次のメソッドを追加します。
[Test]
public void TestPlayerInstantiation()
{
GameObject の characterInstance = GameObject.Instantiate(character, Vector3.zero, Quaternion.identity);
Assert.That(characterInstance, !Is.Null);
}
ついでに、サンプル テンプレートのテスト メソッドをクリーンアップすることもできます。CharacterTestsSimplePasses メソッドと CharacterTestsWithEnumeratorPasses メソッドを削除します。
スクリプトを保存し、エディターの テスト ランナー ウィンドウに戻ります。TestPlayerInstantiation テストを強調表示し、[選択した項目を実行] をクリックします。
緑色のチェックマークはテスト合格を意味します。キャラクターはリソースからロードでき、テスト シーンにインスタンス化でき、その時点では null ではないと主張しました。
このテストでは、[UnityTest] アノテーションではなく [Test] アノテーションが使用されていることに気づいたかもしれません。UnityTest 属性を使用すると、コルーチンで複数のフレームにわたってテストを実行できます。この場合、文字をインスタンス化し、それがロードされたことをアサートするだけです。
通常、特別な指示を出す必要がある場合、フレームをスキップする必要がある場合、または再生モードで一定時間待機する必要がある場合を除き、編集モードでは UnityTest 属性ではなく NUnit Test 属性を使用する必要があります。
次に、UnityTest を使用して、前進コントローラー キーを押したままにするとキャラクターが前進することをアサートします。
以下に示す新しいテスト メソッドを CharacterTests クラスに追加します。
2 つの新しいテスト ヘルパー メソッド、Press() と Release() が登場しました。これらは両方とも InputTestFixture 基本クラスによって提供され、InputSystem コントロールの押下と解放をエミュレートするのに役立ちます。
TestPlayerMoves() メソッドは次のことを行います。
キャラクタープレハブからキャラクターのインスタンスをインスタンス化します。(バツ:0、Y:0, Z:0)
仮想キーボードの上矢印キーを1秒間押して放します
さらに1秒待ちます(キャラクターが減速して動きを止めるまで)
キャラクターが Z 軸上で 1.5 単位を超える位置に移動したことをアサートします。
ファイルを保存し、テスト ランナーに戻って新しいテストを実行します。
次に、シンプルな Player Health コンポーネントを追加して、カスタム Monobehaviour スクリプトをテストします。
Assets/StarterAssets/ThirdPersonController/Scriptsの下に新しいスクリプトを作成します。PlayerHealthという名前を付けます。
IDE でスクリプトを開き、内容を以下のコードに置き換えます。
ここには多くの新しいコードが追加されています。要約すると、このスクリプトはプレイヤーキャラクターが落下状態にあるかどうかを判断します。落下状態で地面に一度当たると、キャラクターの体力が 10% 減少します。
Assets/Resourcesの下にある Character Prefab を見つけます。プレハブを開き、新しい PlayerHealth スクリプト コンポーネントを追加します。
次に、テスト シーンを使用して、棚から落ちた後にプレイヤーの体力が低下することを確認します。
[UnityTest] 属性を使用すると、落下ダメージをテストする再生モード テストを作成できます。0.2 秒以上落下すると、プレイヤーは 0.1f のダメージ (最大体力の 10% に相当) を受けることになります。
SimpleTesting シーンでは、棚に続く階段が表示されます。これは、キャラクターを生成し、PlayerHealth スクリプトをテストするためのテスト プラットフォームです。
CharacterTests.cs をもう一度開き、TestPlayerFallDamage という名前の新しいテスト メソッドを追加します。
[UnityTest]
public IEnumerator TestPlayerFallDamage()
{
// テストシーン内の十分に高い領域にキャラクターを出現させる
GameObject の characterInstance = GameObject.Instantiate(character, new Vector3(0f, 4f, 17.2f), Quaternion.identity);
// PlayerHealth コンポーネントへの参照を取得し、現在フルヘルスであることを確認します (1f)
var characterHealth = characterInstance.GetComponent<PlayerHealth>();
Assert.That(characterHealth.Health, Is.EqualTo(1f));
// 崖から降りて落ちるのを待つ
(keyboard.upArrowKey) を押します。
新しい WaitForSeconds(0.5f) を返します。
Release(keyboard.upArrowKey);
新しいWaitForSeconds(2f)を返します。
// 落下ダメージにより体力ポイントが 1 ポイント失われたことをアサートします
Assert.That(characterHealth.Health, Is.EqualTo(0.9f));
}
また、クラス ファイルの一番上に StarterAssets 名前空間への using 参照を追加する必要があります。
StarterAssets を使用する;
上記のテストは、テストでよく見られる典型的な 配置、動作、アサート (AAA) パターンに従います。
単体テスト メソッドのArrangeセクションは、オブジェクトを初期化し、テスト対象のメソッドに渡されるデータの値を設定します。
Actセクションでは、配置されたパラメータを使用してテスト対象のメソッドを呼び出します。この場合、テスト対象のメソッドの呼び出しは、プレイヤーが落下後に地面に着地したときに物理的な相互作用によって処理されます。
Assert セクションでは、テスト対象のメソッドのアクションが期待どおりに動作することを確認します。
エディターに戻り、新しいテストを実行します。プレイ モードで実行すると、キャラクターが端から落ちて転倒し (転倒と分類される 0.2 秒のしきい値を超える)、地面にぶつかってダメージを受ける様子がわかります。
テストは、コードの変更によって機能が損なわれないことをテストする目的だけでなく、開発者が設定を微調整する際にゲームの他の側面について考えるのに役立つドキュメントや指針としても機能します。
テスト スイートの構築を開始したら、次のステップは、ビルドが完了した後にそれらを自動的に実行することです。ビルド後に実行される自動化された単体テストと統合テストは、回帰やバグをできるだけ早く検出するのに役立ちます。クラウド内のリモート自動ビルド システムの一部として実行することもできます。
多くの場合、テスト実行結果をカスタム形式でキャプチャして、結果をより広いユーザーと共有できるようにする必要があります。Unity エディターの外部でテスト結果をキャプチャするには、ビルドと実行のプロセスを分割する必要があります。
Tests プロジェクト フォルダーに SetupPlaymodeTestPlayerという名前の新しいスクリプトを作成します。
SetupPlaymodeTestPlayer クラスは、ITestPlayerBuildModifier インターフェイスを実装します。これを使用して、ビルドのプレーヤー オプションを受け取って変更できるようにする ModifyOptions メソッドをオーバーライドして「フック」します。
System.IO を使用します。
UnityEditor を使用します。
using UnityEditor.TestTools;
[組み立て:TestPlayerBuildModifier(typeof(SetupPlaymodeTestPlayer))]
パブリッククラスSetupPlaymodeTestPlayer:ITestPlayerBuildModifier
{
パブリック BuildPlayerOptions ModifyOptions(BuildPlayerOptions playerOptions)
{
playerOptions.options &= ~(BuildOptions.AutoRunPlayer | BuildOptions.ConnectToHost);
var buildLocation = Path.GetFullPath("TestPlayers");
var fileName = Path.GetFileName(playerOptions.locationPathName);
if (!string.IsNullOrEmpty(fileName))
buildLocation = Path.Combine(buildLocation, fileName);
playerOptions.locationPathName = buildLocation;
playerOptions を返します。
}
}
このカスタム Player Build 修飾子スクリプトは、テストがプレイ モードで実行されるときに次の処理を実行します (実行場所:プレーヤー上):
ビルドされたプレーヤーの自動実行を無効にし、実行中のホストに接続しようとするプレーヤーオプションをスキップします。
ビルド パスの場所をプロジェクト内の専用パスに変更します (TestPlayers)
これが完了すると、ビルドが完了するたびに、ビルドが TestPlayers フォルダーに配置されるようになります。これでビルドの変更が完了し、ビルドと実行の間のリンクが切断されます。
次に、結果レポートを実装します。これにより、テスト結果をカスタムの場所に書き出すことができ、自動レポート生成と公開の準備が整います。
Tests プロジェクト フォルダーに ResultSerializer という名前の新しいスクリプトを作成します (以下を参照)。このクラスは、TestRunCallback へのアセンブリ参照を使用し、ITestRunCallback インターフェイスを実装します。
この ITestRunCallback の実装には、カスタマイズされた RunFinished メソッドが含まれています。このメソッドは、テスト結果を testresults.xmlという名前の XML ファイルに書き出すためのテストを含むプレーヤー ビルドを設定します。
SetupPlaymodeTestPlayer.cs と ResultSerializer.cs を組み合わせることで、ビルド プロセスと実行プロセスが分割されるようになりました。テストを実行すると、プレーヤー プラットフォームの Application.persistentDataPath の 場所にある testresults.xml に結果が出力されます。
これらのフック クラスの一部の型を使用するには、Tests.asmdefへの追加の参照を追加する必要があります。これを更新して、UnityEditor.UI.EditorTests アセンブリ定義参照を追加します。
プレーヤーでテストを実行すると、プロジェクトの TestPlayers フォルダーにプレーヤー ビルド出力が生成され、Application.persistentDataPath の場所に testresults.xml ファイルが生成されます。
Unity テストフレームワーク コース
テスト フレームワーク パッケージには、Unity を使用したテストについてさらに詳しく学習するのに役立つサンプル演習を備えた テスト コース が含まれています。必ずパッケージ マネージャーを使用してコースのプロジェクト ファイルを取得してください。
パッケージマネージャーの使用>パッケージ:ユニティレジストリ>テスト フレームワークで、サンプル ドロップダウン リストを見つけて、コースの演習をインポートします。
演習はプロジェクトにインポートされ、Assets/Samples/Test Frameworkの下に配置されます。各サンプルには、作業用の練習フォルダーと、手順に従いながら自分の作業と比較するためのソリューションが含まれています。
UTFでコードをQAする
この Unite Copenhagen での UTF に関する講演では、 さらに詳しく説明され、テストのカスタマイズに関するその他の興味深い使用例が紹介されています。他に何ができるかをぜひチェックしてみてください。
Unity でのデバッグ
以下の記事を参考にして、Unity でのデバッグワークフローをスピードアップしましょう。
- Microsoft Visual Studio 2022
- Microsoft Visual Studio Code
高度な技術電子書籍
Unity は、プロの開発者がゲームコードを最適化するのに役立つ高度なガイドを多数提供しています。C# スタイル ガイドを作成します。スケーラブルなクリーンなコードを書く チームがクリーンで読みやすく、スケーラブルなコードベースを開発できるように、コード スタイル ガイドを作成する方法について業界の専門家からのアドバイスをまとめています。
ユーザーの間で人気のあるもう 1 つのガイドは 、「Unity で生産性を高める 70 以上のヒント」です。経験豊富な開発者でも見逃していたかもしれないヒントも含め、Unity 2020 LTS を使用した日常の集約ワークフローを改善するための時間節約のヒントが満載です。
ドキュメント
最新の TestRunner API をさらに詳しく調べ、他の UTF カスタム属性について学び、UTF ドキュメントでフックする追加のライフサイクルを見つけてください。
Unity の高度な電子書籍と記事はすべて 、Unity ベストプラクティス ハブで見つかります。