Unity でUnitTest とML-Agents を使用する時の参照トラブル対応

Unity で単体テスト環境を構築した後、ML-Agents を使ってゲーム上のNPU をAI化しようとして嵌ったので、顛末を共有します。

# 概要

- Unity で単体テスト環境を構築
- ML-Agent をプロジェクトに追加してAgent クラスを参照しようとしたらnamespace が見つからない問題が発生
- ML-Agent 内に鎮座していたAssembly Definision Filesを参照させるようにして問題解決

# Unity で単体テスト環境を構築

## テストコードを格納するためのディレクトリを作成する

まず、Unity のProject ツリーにて、テスト環境を格納するためのディレクトリを作成します。この時、通常のディレクトリ作成手順（Create -> Folder）ではなく、Create -> Testing -> Tests Assembly Folder と選択することでテスト環境用のディレクトリを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143965/08f7612d-ce6b-80e5-c551-1473518fc840.png)

ディレクトリが作成された際、ディレクトリの中にTests.asmdef という名前のAssembly Definition Files （以下adf）が作られています。このadf によって、Unity のTestRunner がリンクされ、単体テストを実行できるようになります。適宜本ディレクトリ内にテストコードを追加していきましょう（本稿では単体テストそのものについては省略します）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143965/413e2ef0-e9f5-fc1e-0d4a-e726df8d06c1.png)

## テスト対象のディレクトリを準備する

上記の手順でadf を作成すると、テストシナリオ用のdll (以下、テストシナリオ.dll)が作られるようになります。ここで、テストシナリオ.dll と周辺のdll との関係は以下の図のようになっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143965/912de900-22ab-1668-51a2-a3571de2e7c8.png)

この時点では、テスト対象のコード群は図の「その他大勢」に含まれてしまっており、テストシナリオ.dllから参照することができません。そのため、テスト対象のコード群を独立したdll として分離し(以下、テスト対象.dll)、テストシナリオ.dll から参照するように設定する必要があります。下記がそのイメージ図です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143965/a078f0c1-01e4-6783-a474-5f04d06a4e8d.png)

テスト対象を分離させるには、テスト対象のソースコードを特定のディレクトリ以下に配置し、このディレクトリ直下に新たにadf を作成します。今回はテスト対象のadf ファイル名をTarget.asmdef とします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143965/dcdb651e-48a3-37ce-f293-125f861d23d1.png)

続いて、テストシナリオ側(Tests.asmdef)からテスト対象(Target.asmdef)を参照できるように、Unity のエディタ上でTarget.asmdef をTests.asmdef のAssembly Definition References に追加します。既にTestRunner がリストに存在していると思うので、リストに追加する形になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143965/9597e17d-fe5c-44f4-e54b-9dc15d10bb94.png)

# ML-Agent をプロジェクトに追加

[GitHub のUnity-Technologies / ml-agents](https://github.com/Unity-Technologies/ml-agents/blob/main/com.unity.ml-agents.extensions/Documentation~/com.unity.ml-agents.extensions.md)を参考にして、ML-Agents をUnity のプロジェクトに追加してください。

そして、自分のソースコードからAgent クラスを参照しようとしたらnamespace が見つからないと怒られます。。。

```
using UnityEngine;
using UnityTetris.Abstract;
using UnityTetris.Interface;
using Unity.MLAgents;
using Unity.MLAgents.Sensors;

public class MLInput : Agent, IInputManager
{
```

「namespace ML-Agents が見つからない」と怒られますね。。。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143965/d8279f7a-39f1-45bc-f547-f90d31879a5e.png)

今回の単体テスト環境構築により、自分のソースコードがTarget.asmdef によりAssembly-Csharp.dll (いわゆるその他大勢)から分離されてしまうため、ML-Agents を参照するように明示的に設定を行う必要があります。

#  ML-Agents を参照するように設定する

実は、プロジェクトビューのPackages 以下にあるML Agents 内にもUnity.ML-Agents.asmdef というadf があるので、これをTarget.asmdef から参照するように設定する必要があります。Target.asmdef をInspector で表示し、この中にあるAssembly Definition References のリストにUnity.ML-Agents.asmdef を追加してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143965/da10d6a2-57f8-cf6b-a33d-b36a7a74d043.png)

これにより、自分のソースコードからML-Agents を参照することができるようになります。各dll の関係は以下のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143965/d49467e8-d717-b36e-fb94-52caf6c63e1d.png)

ML-Agents 以外のパッケージを使用する場合でも同様の理屈で参照設定する必要がありますので、単体テスト環境を構築した場合は注意しましょう。

# 参考ページ

- [Unity Assembly Definition 完全に理解した](https://qiita.com/toRisouP/items/d206af3029c7d80326ed)