EditModeTestで楽をしよう

# はじめに
EditModeTestを利用することで実装の確認などで楽になることがありました。
今回はEditModeTestを利用して少しでも楽をしようという内容になっています。

注意点：
テストをしやすいデータ構造の紹介などは行いません。
簡単なテストのみ行います。

# 使用したバージョン
Unity 2018.2.11f1

# テストのための設定
まずはテストを行うための設定を行っていきます。
メニューバーから`Window > General > Test Runner`を選択します。

![launch-test-runner.jpg](https://qiita-image-store.s3.amazonaws.com/0/111339/7b1203b1-a8ca-bb63-a5eb-a8ae1085b1e5.jpeg)

Test Runnerウィンドウが表示されたと思います。
テスト用のスクリプトを入れるフォルダを作成するため、ウィンドウ内の`Create EditMode Test Assembly Folder`ボタンを押します。

![test-runner-1.jpg](https://qiita-image-store.s3.amazonaws.com/0/111339/0ccc3ffa-e8da-7fd2-c3bf-870977aa4f5c.jpeg)

プロジェクト内に`Assets/Tests`フォルダが作成されていると思います。
Testsフォルダ内にテスト用のAssembly Definitionも作成されていると思います。
テストに利用するスクリプトはこちらのTestsフォルダ内に作成していきます。

![test-folder-1.jpg](https://qiita-image-store.s3.amazonaws.com/0/111339/c3846dba-68a6-059d-f223-ff5b3c5ac2cf.jpeg)

これでEditMode Testを行う準備ができました。

# ダメージ計算っぽいものを作ってみる
プレイヤーキャラクターからエネミーキャラクターへのダメージ計算処理について考えてみます。
仕様は以下です。

- プレイヤーの攻撃力からエネミーの防御力を引いたものが基礎ダメージ
- プレイヤーとエネミーの属性相性が良ければダメージが1.5倍、普通ならダメージは1倍、悪ければ0.5倍
- ステータスは現状では外部から受け取ることができないので、決め打ちでOK

そのためこのようなコードを書いていました。

```cs:BattleDirector.cs
using UnityEngine;

public class BattleDirector : MonoBehaviour
{
    private Player _player;
    private Enemy _enemy;

    private void Start()
    {
        _player = new Player { Attack = 10000, Attribute = CharacterAttribute.Red };
        _enemy = new Enemy { Hp = 10000, Defense = 5000, Attribute = CharacterAttribute.Green };
    }

    public void PlayerAttack()
    {
        var damage = CalcLogic.CalcPlayerAttackDamage(_player, _enemy);
        _enemy.Hp -= damage;
    }
}
```

```cs:CalcLogic.cs
using System.Collections.Generic;
using UnityEngine;

public class CalcLogic
{
    private static readonly List<List<float>> CharacterAttributeRateTable = new List<List<float>>
    {
        new List<float>{1.0f, 1.5f, 0.5f},
        new List<float>{0.5f, 1.0f, 1.5f},
        new List<float>{1.5f, 0.5f, 1.0f},
    };

    public static int CalcPlayerAttackDamage(Player attacker, Enemy defender)
    {
        var baseDamage = attacker.Attack - defender.Defense;
        var damage = baseDamage * GetCharacterAttributeRate(attacker.Attribute, defender.Attribute);
        return Mathf.FloorToInt(damage);
    }

    private static float GetCharacterAttributeRate(CharacterAttribute attackerAttribute, CharacterAttribute defenderAttribute)
    {
        return CharacterAttributeRateTable[(int)attackerAttribute - 1][(int)defenderAttribute - 1];
    }
}
```

```cs:Characters.cs
public enum CharacterAttribute
{
    None, Red, Green, Blue
}

public class Enemy
{
    public int Hp { get; set; }
    public int Defense { get; set; }
    public CharacterAttribute Attribute { get; set; }
}

public class Player
{
    public int Attack { get; set; }
    public CharacterAttribute Attribute { get; set; }
}
```

プレイヤーが攻撃するタイミングで`BattleDirector.PlayerAttack()`を呼び出すことでダメージ計算を行い、エネミーにダメージを与えるようになっています。

ダメージ計算が正しく行われているか確認する場合は、いちいちBattleDirector内で定義されているプレイヤーやエネミーのパラメータを変更してプレイするというのを何度か繰り返す必要があります。
スクリプトのコンパイル時間や画面遷移などの時間を考えると少なくない時間がかかってしまいます。

# ダメージ計算のテストを作成してみる
ダメージ計算のテストを作成して、ダメージ計算の確認の時間を減らしてみたいと思います。
今回は`CalcLogic.CalcPlayerAttackDamage`のテストなので、そのままでも問題ありませんが、テストを行う処理はテストスクリプトからアクセスできる状態にする必要があります。
（publicメソッドにしたり、リフレクションなどを利用したりします。）

テスト用のスクリプトをAssets/Testsフォルダに以下に作成します。

```cs:CalcDamageTest.cs
using NUnit.Framework;

public class CalcDamageTest
{
    [TestCase(CharacterAttribute.Red, 5000)]
    [TestCase(CharacterAttribute.Green, 2500)]
    [TestCase(CharacterAttribute.Blue, 7500)]
    public void 属性の違いによるダメージ計算テスト(CharacterAttribute playerAttribute, int expectedDamage)
    {
        var player = new Player { Attack = 10000, Attribute = playerAttribute };
        var enemy = new Enemy { Defense = 5000, Attribute = CharacterAttribute.Red };

        var damage = CalcLogic.CalcPlayerAttackDamage(player, enemy);
        Assert.AreEqual(expectedDamage, damage);
    }
}
```
プレイヤーの属性によってダメージ量が正しく計算できるかのテストを作成しました。
（テストの細かい書き方などは、NUnitなどで調べてみてください。）

作成したテストはTest Runnerで実行することができます。
TestCaseで指定した分のテストがリストに表示されています。

![test-runner-2.jpg](https://qiita-image-store.s3.amazonaws.com/0/111339/3d7f0358-463c-f8d0-aa89-39749b7d3d26.jpeg)

Run Allボタンなどからテストを実行します。
テストが無事に完了すると緑のチェックマークが付きます。

以前のように「パラメータを変更して実行する」を繰り返す必要がなくなり、テストを作成する時間が必要となりました。
ダメージ計算処理に仕様追加などがあった場合は、このテストにテスト項目を追加することで実装の確認が楽になります。

# まとめ
- テストを行う環境はTest Runnerから1ボタンで作成できる
- テストを行う処理はテストスクリプトからアクセスできる必要がある
- いくつかのパターンを確認するなどテストを利用すると楽ができる
- 仕様変更などの実装確認でも楽ができる