やらなイカ?

たぶん、iOS/Androidアプリの開発・テスト関係。

Unity 2018のUnity Test Runner

ようやく重い腰を上げて手元のUnity 2017.4プロジェクトを2018.3に移行したので*1何番煎じかわからないけどテスト(Unit tests)まわりについてまとめ。

Test Runnerウィンドウ

2017ではメニューのWindow直下にあった"Test Runner"ですが、Window > General > Test Runnerに移動されました。

Edit mode Tests

2017.4までは、EditModeで実行するテストコードはAssets/**/Editor/**/下にあればよかったのですが、2018では条件が増えています。

例えばAssets/Xxx/Editor/のようなフォルダ階層でXxx下にAssembly Definition(以下asmdef)ファイルを置いてしまうと、Editorまで同じアセンブリに含まれてしまいます。

Xxx/Editor下にEdit mode Testsがある場合はXxx/Editor直下にもうひとつadmdefファイルを作り*2、"Test Assemblies"と"Editor"の2つのチェックボックスをonにする必要があります。

f:id:nowsprinting:20190402003537p:plain

なお、Edit modeでは[UnityTest]属性をつけたテストはEditorApplication.updateコールバックループで実行されるという点は2017も2018も同様です。

Play mode Tests

2017ではPlay modeでテストを実行するには”Enable playmode tests”をクリックしてから再起動する手順が必要でしたが、2018では不要になっています。

代わりに、テストコードは任意のフォルダ下に置き、そこにadmdefファイルを作り、"Test Assemblies"チェックボックスをonにする必要があります。

f:id:nowsprinting:20190402003606p:plain

なお、Play modeでは[UnityTest]属性をつけたテストはコルーチンで実行されるという点は2017も2018も同様です。

Enable playmode tests for all assemblies

もし、Play modeのテストコードを容易に移動できない、asmdefによってアセンブリを分けることが困難といった場合、Test Runnerウィンドウ右上のハンバーガーメニューから"Enable playmode tests for all assemblies"をクリックして有効にすることで、Unity 2017のようにモードを切り替えてPlay mode Testsを実行することができるようです(未確認)。

f:id:nowsprinting:20190402003321p:plain

ただし、このままではビルドに追加のアセンブリが含まれるため、プロジェクトのサイズとビルド時間が長くなってしまいますので、ビルドを行なうときにはDisableに戻すべきです。

アセンブリの依存関係

asmdefはUnity 2017.3から導入された機能で、アセンブリを小分けすることでプロジェクトのビルド時間を節約する効果があります。

Unity 2018からはテストコードは専用のアセンブリ("Test Assemblies"チェックボックスをonにしたもの)に属する必要が生じたため、テストコードのasmdefからSUT(system under test: テスト対象)ほか使用しているasmdefを参照する旨を"Assembly Definition References"に設定する必要があります。

下図はSUTである"SUTClient"と、"UniRx"に依存している例です。

f:id:nowsprinting:20190402021134p:plain

Internalの扱い

C#では、Internalアクセス修飾子をつけたclass/methodは同一アセンブリ内からのみ参照できます。Unity 2018でテストコードが別アセンブリになったことによって、そのままではInternalなclass/methodのテストを書くことができません*3

これに対し、参照される側(SUT)の中に以下のコードを書くことで、指定したアセンブリに対してInternalなclass/methodを公開することができます。

using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("Assembly-CSharp-Editor")]
[assembly: InternalsVisibleTo("SampleTestsAssembly")]

""の中には、公開するアセンブリ(この文脈上はテストコードのアセンブリ)名を書きます。"Assembly-CSharp-Editor"はエディタです。

なお、このコードはアセンブリ内のどのファイルに書いても良いようなのですが、過去の経緯から"AssemblyInfo.cs"というファイルに書くことが多い? ようです。

おまけのTips

*1:2017.4から2018.3に上げたので、差分は2018.1か2か3のどこで入ったものかまでは確認していません

*2:右クリック > Create > Assembly Definition

*3:Unity 2017以前でも、Edit modeのテストコードはAssembly-CSharp-Editorというアセンブリに入るため、Internalなclass/methodのテストはそのままテストできませんでした