Nodachisoft Nodachisoft logo, Katana Sword Icon
  
@あまじ✎ 2021年12月27日に更新

Unity で Unity Testing Framework(UTF)を使ってEdit Mode のテスト、Play Mode のテストコードを書いて動かす

Unity で Unity Testing Framework(UTF)を使ってEdit Mode のテスト、Play Mode のテストコードを書いて動かす

概要

Unity で開発するときも、他のアプリ開発同様、単体テストを書くことで、 下のようなメリットがあります。

  1. モジュールの品質向上
  2. モジュールの仕様・挙動の明確化
  3. モジュール実装の(将来的な)リファクタリングをしやすく
  4. モジュール開発の高速化
  5. Unity がバージョンアップしたときの動作確認

他にもいろいろメリットがあると思いますが、私が感じるメリットはこんな感じです。

Unity Testing Framework

Unity で通常、使用される Testing Framework として、UTF(Unity Testing Framework) があります。

UTF は .NET 開発のテストフレームワークである、NUnit をベースにしています。

Unity 2019.2 以降のバージョンでは、UTF を使うには個別パッケージでプロジェクトにインストールしておく必要があります。 ただ、Unity 2020.3 LTS では Unity HUB からプロジェクトを作成するときに選択したテンプレートでは既にインストールされていました。(テンプレートによっては含まれていないものもあるのかも?)

自分の環境で UTF が使えるかを確認してみます。 Unity のメニューから、Window -> Package Managerを選択して

Package Manager

Package Manager のウィンドウのメニューにある、 Packages: から Unity Registry を 選択し、ウィンドウ右上の検索バーにTest Framework と入れると テストフレームワークが一覧に表示されます。

Search in Package Manager

既に緑のチェックマークが入っている場合は、インストール済みです。 入っていなければ、Install ボタンで導入できます。

特徴

UTF を導入し、テストコードを書くことで、Unity 機能を使った単体テストを実施できます。 いちいち、本番プログラム内にテスト検証コードを含むことなく、 モジュール機能の検証や結果を確認できます。

UTF には 2 つの実行モードがあります。Edit ModePlay Mode があります。

Edit Mode

Unity Editor を編集中のモード(Edit Mode)のままテストを実行できます。 いちいちゲームを実行しなくてもテストを実行できるので便利です。

Play Mode

プロジェクトを Play(実行)したときのゲーム内の状態に併せたテストができます。 UnityTest 属性をつけると、コルーチンとしてテストコードが実行されるようになります。

Edit Mode のテストを実行するまでの流れ

まずは、テストを実行したり一覧を表示するためのウィンドウを表示してみます。

Unity Editor のメニューからWindow -> General -> Test Runner を選択すると、Test Runner というウィンドウが開きます。

Test Runner

Create EditMode Test Assembly Folder ボタンを押すと、 現在、プロジェクトで開いている場所にテストコードを作成するためのフォルダが作成されます。

new Tests folder

この Tests フォルダの中にはデフォルトで、Tests.asmdef という拡張子「asmdef」のファイルが出来ています。これはアセンブリ定義ファイルと呼ばれ、Unity の Assembly Definition(略して adf ) と呼ばれる機能の設定を記述しており、ここにテストのアセンブリへの依存関係を定義することで、必要最小限の DLL 呼び出しができます。

asmdef の設定

アセンブリ定義ファイル(asmdef ファイル)に、テストを実行するために必要なアセンブリへの参照を追加しておく必要があります。 またテストモードが Edit Mode の場合、このフォルダ配下のテストスクリプトが Edit Mode での実行となることを設定しておきます。

Unity Editor 上で asmdef ファイルを選択すると、インスペクタに テストコードから参照するアセンブリや実行プラットフォームの設定ができます。

EditrModeInspector

Editor にチェックを入れておきます。(デフォルトで入っているかと思います)

Edit Mode のテストコード新規作成

続いて、テストコードを作成します。

Test Runner のウィンドウ上から Create Test Script in current folder ボタンを押します。

Create NewTestScript

新しく NewTestScript.cs ファイルが生成されます。名前を適当に変更します。

コードの中身はデフォルトで以下のようになっています。

 
NewTestScript.cs
using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;

public class NewTestScript
{
    // A Test behaves as an ordinary method
    [Test]
    public void NewTestScriptSimplePasses()
    {
        // Use the Assert class to test conditions
    }

    // A UnityTest behaves like a coroutine in Play Mode. In Edit Mode you can use
    // `yield return null;` to skip a frame.
    [UnityTest]
    public IEnumerator NewTestScriptWithEnumeratorPasses()
    {
        // Use the Assert class to test conditions.
        // Use yield to skip a frame.
        yield return null;
    }
}

[Test][UnityTest] の Attribute(属性)がついている、 2つのメソッドがあります。 この2つがテストコードとなっており、

Test Runner ウィンドウ上の一覧から確認、実行ができます。

Test Runner Test List

ウィンドウ上で実行したいテストを 右クリック -> RUN を 選択すると、テストを実行できます。

結果、緑のチェックが表示され、テストが成功したことがわかります。

Test Result

また、ウィンドウの上部にある Run All をクリックすれば、すべてのテストコードが実行されます。

通常の NUnit テストコードを書いてみる

Unity 関係なく C# 開発で利用できる、通常の NUnit のコードを書いてみます。

参考として、[Test] Attribute がついたテストを2件作成。

Edit Mode、Play Mode の両方で動かすことができます。

以下のようにテストケースを作ります(先ほどのテストコードを書き換えます)

 
NewTestScript.cs
using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;

public class NewTestScript
{
    [Test]
    public void Test1_Equal() {
        Debug.Log("Here is my first Test!");
        Assert.That( 5*20, Is.EqualTo(100));
    }

    [Test]
    public void Test2_Equal() {
        Debug.Log("Here is my second Test!");
        Assert.That(3, Is.InRange(5,10));
    }
}

実行すると、Test2_Equal のテストケースは失敗していることが判りました。

Test Error

テストコードには以下のような NUnit 3.0 の Assert を使用できます。

例としてはこんな感じ。

Assert.That(100, Is.EqualTo(5 * 20));

数値 1005 * 20 と同じなら検証OK、ということになります。

NUnit 2 の Assert 機能(Classic Model) NUnit 2 の Assert 機能(Classic Model)を使ったテストの検証コードも引き続き使えますが、新しい NUnit 機能がシンプルにテストを書けることや、新機能は(後方互換のため?)今後、Classic Model での書き方では適用されないため、公式では NUnit 3~ の書き方を推奨しているようです。
NUnit の Classic Model な Assertion の機能一覧はコチラ(nunit.org 公式)

テスト実行結果の確認、デバッグログ出力

Unity の Test Runner ウィンドウ上からテストの成功、失敗したときの 状況やデバッグログ出力内容を確認できます。

Test Runner で失敗したケースを選択してみます。

Testcase Result

Test2_Equals のテストケースをクリックして確認してみると Assert.That が失敗した比較の内容について出力されています。

また、テストケース内で記述した Debug.Log の内容もここで確認できます。

Nunit3 の書き方

NUnit3 では基本的に Assert.That を利用します。

assert.that
Assert.That( 結果 , 期待される制約 );

よく使う制約(Constraint)の書き方を書いておきます。

記述例 例の意味
Assert.That( a, Is.EqualTo( 2 )); a が 2 と等しい
Assert.That( b, Is.InRange( 5,10)); 5 <= b <= 10
Assert.That( new List(){1,2,3}, Has.Member(2) ); リスト(1,2,3) に 要素 2 が含まれる
Assert.That( c, Is.Not.EqualTo(3) ); c が 3 と等しくない
Assert.That( d, Is.EqualTo(1).Or.EqualTo(2)); d は 1 OR 2
Assert.That( e, Is.GreaterThan(3).And.LessThan(5) 3 <= e AND e <= 5

Edit Mode、Play Mode のテストコードからの他モジュールへの参照

例えば Edit Mode から別のスクリプト内の機能を確認するとき、 うまくクラスを参照できない(解決できない)場合があります。(Play Mode のテストでも同様)

エラー例
Assets\NodachiFramework\common\unity_util\Tests\OperateHierarchyTest.cs(6,7): error CS0246: The type or namespace name 'NodachiFramework' could not be found (are you missing a using directive or an assembly reference?)

プロジェクトのアセンブリ定義ファイル(asmdef ファイル)を作っておき テスト用アセンブリ定義ファイルからの参照を設定します。

ゲーム用のAssetフォルダ配下が以下のようなフォルダ構成のとき 「CommonUtil.cs」をテストしたいとします。

Script
  +- CommonUtil.cs
Tests
  +- EditTest
  |   +- MyEditTestAssembly.asmdef
  |   +- SampleEditTest.cs
  |
  +- PlayTest
      +- PlayTestAssembly.asmdef
      +- SamplePlayTest.cs

Script の配下には ゲームプロジェクトで使う様々なスクリプトが入っているとし、 Script 直下にアセンブリ定義ファイルを新規作成します。

Unity の Project 上から、Scriptフォルダ右クリック -> Create -> Assembly Definition で新規にアセンブリ定義ファイルを作ることができます。

テスト用に作成した PlayTestAssembly.asmdef のインスペクタから、 Assembly Definition References の + ボタンから 先ほど Script 配下に作った Assembly Definition を追加します。

PlayTestAssembly

これでテストコードからプロジェクトのScript フォルダ配下のクラスについても参照できるようになりました。

Play Mode のテストを実行するまでの流れ

ゲームを実行した時の状態についてテストする流れを確認していきます。

サンプルのプロジェクト構成

以下のようなプロジェクトの構成があったとします。

Resources
  +- Prehabs
     +- Bomb
Script
  +- BombBehavior.cs

Bomb(爆弾)のプレハブには、スクリプト「BombBehavior.cs」がアタッチされており、 時間がたつと爆発する!という簡単なものを想定しています。 今回は、この BombBehavior.cs の挙動をテストします。

確認用に Tests フォルダをプロジェクト直下に作ります。 (別に場所は自由です)

Resources
  +- Prehabs
     +- Bomb
Script
  +- BombBehavior.cs
Tests

Unity Editor のメニューからWindow -> General -> Test Runner を選択して、Test Runner というウィンドウを開きます。

プロジェクトから Tests フォルダを選択した状態で、

Test Runner のウィンドウを開いたら、PlayModeを選択し、 Create PlayMode Test Assembly Folderを選択します。

Create PlayMode Test Assembly Folder

新しく「Tests/Tests」フォルダが出来ますので、リネームして「Tests/PlayTests」に変更しました。

Resources
  +- Prehabs
     +- Bomb
Script
  +- BombBehavior.cs
Tests
  +- PlayTests
      +- PlayTests.asmdef

Script フォルダ配下の、「BombBehavior.cs」スクリプトの内容をテストしたいので、 テストコードから参照できるように、 Script直下にアセンブリ定義を作成しておきます。

Scriptフォルダ右クリック -> Create -> Assembly Definition で新規にアセンブリ定義ファイルを作っておきます。 (当記事内の「Edit Mode、Play Mode のテストコードからの他モジュールへの参照」の項目ご参照)

Resources
  +- Prehabs
     +- Bomb
Script
  +- BombBehavior.cs
  +- MyGameAssembly.asmdef
Tests
  +- PlayTests
      +- PlayTests.asmdef

「PlayTests.asmdef」のインスペクタを開き、Script直下の「MyGameAssembly.asmdef」を Assembly Definitiono Reference に追加します。

続いて、PlayTests フォルダの中に、テストコードを書くための「SamplePlayTest.cs」を作成。

Resources
  +- Prehabs
     +- Bomb
Script
  +- BombBehavior.cs
Tests
  +- PlayTests
      +- PlayTests.asmdef
      +- SamplePlayTest.cs

以下のようなコードを書きました。

 
SamplePlayTest.cs
public class UnityPlayModeTest
{
    [UnityTest]
    public IEnumerator BombTimer_Success()
    {
        GameObject bombPrehab = MonoBehaviour.Instantiate (
            Resources.Load<GameObject>("Prehabs/Bomb"),
            new Vector3( 0.0f, 0.0f, 1.0f),
            Quaternion.identity);
        BombBehavior bombBehavior = bombPrehab.GetComponent<BombBehavior>();
        // (A)まだ爆弾は爆発していない
        Assert.That( bombBehavior.isExploded(), Is.EqualTo(false) );
        yield return new WaitForSeconds(5.0f);

        // (B)5秒だったので爆発している
        Assert.That( bombBehavior.isExploded(), Is.EqualTo(true) );

        GameObject.Destroy(bombBehavior.gameObject);
        yield return null;
    }
}

このテストコードのメソッド BombTimer_Success は、 Prehabs/Bomb のプレハブをテスト用のシーンに生成して、挙動をチェックするテストコードです。

この Bomb プレハブは3秒で爆発し、isExploded() メソッドで爆発しているかどうか、 True / False で 確認できます。

テストケースの中では、11行目の(A)で爆発していないことをチェックし、 15秒目の(B)で爆発していることをチェックしています。

これで Edit Mode と同じように、TestRunner 上からテストできました。

実行すると、テスト用のシーンが立ち上がりしばらくすると結果が出ます。

実行時は、テスト用シーンの中で、爆弾(Bomb)プレハブが生成され、 コルーチンとしてテストコードが呼び出さされて、5秒経過した前後の挙動が確認されます。

参考

変更履歴

日付 変更概要
なし
 
 
送信しました!

コメント、ありがとうございます。

なんかエラーでした

ごめんなさい。エラーでうまく送信できませんでした。ご迷惑をおかけします。しばらくおいてから再度送信を試していただくか、以下から DM などでご連絡頂ければと思います。

Twitter:@NodachiSoft_jp
お名前:
 
連絡先:
 
メッセージ:
 
戻る
内容の確認!

以下の内容でコメントを送信します。よろしければ、「送信」を押してください。修正する場合は「戻る」を押してください

お名前:
 
連絡先:
 
メッセージ:
 
Roboto からの操作ではないという確認のため確認キーを入れてください。
確認キー=95
戻る
 / 
送信確認へ
コメント欄
コメント送信確認へ

関連ありそうな記事(5件)です!

Unity の C# コードで System.Type.GetType が null を返してしまう

Unity の C# コードで System.Type.GetType が null を返してしまう

#Unity#.net✎ 2022-1-11
Unity の C# コードで System.Type.GetType が null を返してしまう
目次
Unity で Unity Testing Framework(UTF)を使ってEdit Mode のテスト、Play Mode のテストコードを書いて動かす
Unity で Unity Testing Framework(UTF)を使ってEdit Mode のテスト、Play Mode のテストコードを書いて動かす
概要
概要
Unity Testing Framework
Unity Testing Framework
特徴
特徴
Edit Mode
Edit Mode
Play Mode
Play Mode
Edit Mode のテストを実行するまでの流れ
Edit Mode のテストを実行するまでの流れ
asmdef の設定
asmdef の設定
Edit Mode のテストコード新規作成
Edit Mode のテストコード新規作成
通常の NUnit テストコードを書いてみる
通常の NUnit テストコードを書いてみる
テスト実行結果の確認、デバッグログ出力
テスト実行結果の確認、デバッグログ出力
Nunit3 の書き方
Nunit3 の書き方
Edit Mode、Play Mode のテストコードからの他モジュールへの参照
Edit Mode、Play Mode のテストコードからの他モジュールへの参照
Play Mode のテストを実行するまでの流れ
Play Mode のテストを実行するまでの流れ
サンプルのプロジェクト構成
サンプルのプロジェクト構成
参考
参考
変更履歴
変更履歴
Nodachisoft © 2021