GitHub Actions を使った Unity の自動テスト

# 概要

　この記事には、GitHub Actions で Unity のテストを自動化する方法・特定のブランチはテストが通らないとマージできないようにする方法が書いてあります。また、おまけとして unitypackage をコマンドラインで作る方法も載せています。

# 背景

　[kumaS-nu/NuGet-importer-for-Unity](https://github.com/kumaS-nu/NuGet-importer-for-Unity) 
　↑のプロジェクトを作ると決めた際、しっかりしたプロジェクトにしたいよね。と思い、自動テストを組み込むことにしました。また、このプロジェクトは以下の記事で宣伝しています。
[Unity のプロジェクトに NuGet のパッケージをインポートするエディタ拡張を作ったよ](https://qiita.com/kumaS-kumachan/items/92f5c7d3875ed6430877)

# 事前準備

　GitHub Actions で Unity のテストを自動化するからには、Unity Test Framework を用いたテストがあるリポジトリを用意します。

## Unity Test Framework

　Unity2018 では Unity Test Runner と呼ばれていましたが、Unity2019 以降では Unity Test Framework というパッケージとなっています。どちらも（たぶん）変わりません。
　ここに関しては本題ではないので軽く説明するだけに留めておきます。

### モード

　Unity Test には Editor Mode Test と Play Mode Test があります。これはそのまんまで、Play Mode Test では Unity を再生してテストをし、Editor Mode Test はエディタ上でテストをします。Play Mode Test は再生モードに移行するタイムラグがあるため、Editor Mode Test に比べて遅いため Editor Mode Test で充分なテストは Editor Mode Test でした方がよいです。

### テストを作る

　テストはデフォルトでないアセンブリ（Assembly-CSharp や Assembly-CSharp-Editor でない）に書いてないといけません。といっても、Unity Test Runner のウィンドウの **Create ** Test Assembly Folder** をクリックすればいいだけですが。作ったフォルダの中に以下のようなテスト作ります。

```csharp
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;

public class SampleTest
{
    [OneTimeSetUp]
    public void SetUp()
    {
        //このクラスが作られるときに一度だけ実行される。
    }

    [UnityTest]
    public void SampleTest1()
    {
        //ここにテストを書く
        var actualString = "Test string";
        Assert.That(actualString, Is.EqualTo("Test string"));
    }

    [UnityTest]
    public IEnumerator FindRequiredPackagesTest01()
    {
        //複数フレーム間にわたりそうなときはこちらを使う。非同期はこちらをうまく使う。
        var waitSecond = 1;
        yield return new WaitForSeconds(1);
        Assert.That(waitSecond, Is.EqualTo(1));
    }

    [OneTimeTearDown]
    public void TearDown()
    {
        //このクラスが削除されるときに一度だけ実行される。
    }
}
```

　実際にテストを作るときは以下の参考資料を元にすればいいと思います。

#### 参考資料

* [【Unity】Unity Test Runner（Test Framework）入門 - インストールから基本的な使い方・注意点まとめ](https://light11.hatenadiary.com/entry/2020/02/21/212657)
* [About Unity Test Framework - Unity 公式](https://docs.unity3d.com/Packages/com.unity.test-framework@1.1/manual/index.html)
* [NUnit Documentation Site - NUnit 公式](https://docs.nunit.org/#user-documentation)


# GitHub Actions で Unity のテストをできるようにする

　では本題です。といっても実は GitHub Actions のマーケットプレースに Unity のテストをするアクションを公開されているのでその使い方の説明です。今回使うのは以下の二つです。（なお、どちらも Unity 公式ではないです。また、この記事を書いてる時点でバージョン 2 のプリリリースがあるのですぐ使い方が変わりそうで不安。）

* [Unity - Request Activation File](https://github.com/marketplace/actions/unity-request-activation-file)
* [Unity - Test runner](https://github.com/marketplace/actions/unity-test-runner)

## Unity - Request Activation File

　Unity は使うのにライセンス認証が必須です。これは Unity をアクティベーションするためのファイルを作ってくれるアクションです。この一連のアクションを開発している Game-CI は v2 以降は [game-ci/docker](https://github.com/game-ci/docker/) を使用していているとのことですが、それ以前は、その前のプロジェクトのものを使用しているため、使える Unity のバージョンに制限があることがあります。
　プライペートなリポジトリでも作って、以下のような Action を作成します。

``` yaml
name: Acquire activation file
on: [push]
jobs:
  activation:
    name: Request manual activation file
    runs-on: ubuntu-latest
    steps:
      - name: Request manual activation file
        id: getManualLicenseFile
        uses: webbertakken/unity-request-manual-activation-file@v1.2
        with:
          #テストで使用する Unity のバージョンを指定。デフォルトは2019.2.11f1。v2未満は 2019.4 系は 14f1 までしかなかった。
          unityVersion: 2019.4.14f1
      - name: Expose as artifact
        uses: actions/upload-artifact@v2.2.2
        with:
          name: ${{ steps.getManualLicenseFile.outputs.filePath }}
          path: ${{ steps.getManualLicenseFile.outputs.filePath }}
```

　これを Actions に登録（コミット）すると、そのプッシュによってこの Action が走り、しばらくするとアーティファクトとして .alf ファイルがアップロードされます。そのファイルをダウンロードし、https://license.unity3d.com/manual にて手動アクティベートをして生成された .ulf ファイルをダウンロードします。
　これらのファイルはライセンス情報を含むので、公開しないように。(･`ω´･@)<ダメ！情報漏洩！

　公式のドキュメントはこちら [Activation - Game CI](https://game.ci/docs/github/activation)


## Unity - Test runner

　このアクションを使用して Unity のテストを走らせます。

### Unity のアクティベーションファイルを設定する

　[先駆者](https://qiita.com/pCYSl5EDgo/items/690dd56ffb0fcf64e70b)たちはこの部分でどう安全するかと苦労していましたが、このアクションは非常に簡単です。
　以下のように、リポジトリの Settings の Secrets にある New repository secret というボタンをクリックします。

![GitHubSecrets1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338159/d3e14ada-39ed-49a4-7006-59a80f0a2a86.png)

　そして、Name になんかいい感じの名前（私は UNITY_LICENSE にしたけど）を入れ、Value に .ulfファイルの中身をコピペします。

![GitHubSecrets2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338159/d718cb31-7371-3acb-67c4-4f130c50a7a7.png)

　これで Action からしか見えず、暗号化されたライセンスが安全に追加できます。

### テストを走らせるアクションを作る

　以下のようなアクションを作ると、テストを走らせれます。

```yaml
name: Test

on:
  # プルリクが作られた・更新されたとき
  pull_request:
    types: [opened, synchronize]
  # mainブランチがプッシュされたとき
  push: { branches: [main] }

env:
  # さっき決めたいい感じの Secrets の名前
  UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}

jobs:
  testAllModes:
    name: Test in ${{ matrix.testMode }} on version ${{ matrix.unityVersion }}
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        projectPath:
          # 走らせるプロジェクトのパス
          - NuGetImporterForUnity
        unityVersion:
          # 使う Unity のバージョン
          - 2019.4.14f1
        testMode:
          # 実行するテストのモード
          - editmode
    steps:
      - uses: actions/checkout@v2.3.4
      - uses: actions/cache@v2.1.4
        with:
          path: ${{ matrix.projectPath }}/Library
          key: Library-${{ matrix.projectPath }}
          restore-keys: |
            Library-
      - uses: webbertakken/unity-test-runner@v1.7
        env:
          UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
        id: tests
        with:
          projectPath: ${{ matrix.projectPath }}
          unityVersion: ${{ matrix.unityVersion }}
          testMode: ${{ matrix.testMode }}
          artifactsPath: ${{ matrix.testMode }}-artifacts
```

　もし、テストがすべて通ったら Action は成功したという風になり、失敗したものがあれば Action は失敗したという風になります。また、これには書きませんでしたがアーティファクトをアップロードするようにすればテストの結果を見ることができます。

公式のドキュメントはこちら [Test runner - Game CI](https://game.ci/docs/github/test-runner)

# テストを通らないとマージできないようにする

　プルリクエストに関係するアクションを作るだけでプルリクエストを作ったときにいい感じにテスト結果を出してくれるのですが、せっかくテストを作ってもテスト結果を無視してマージされたら意味ないです。（どっかのうっかりさんはときどきやるんです (๑´ڡ`๑)<てへ//）
　なので、ブランチの保護もしておくとよりよいです。ということでその説明をします。
　以下のように、リポジトリの Settings の Secrets にある New repository secret というボタンをクリックします。

![branch1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338159/9993a527-093c-efe1-ed4d-69f917d787c6.png)

　そして、branch name pattern に保護したいブランチの名前を入れ、Require status checks to pass before merging・Require branches to be up to date before merging・そしてパスしなければならないテストにチェックを入れ、下の方にある Create ボタンをクリックするとブランチの保護ができます。

![branch2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338159/1f59c362-425a-4b69-2d2d-f16723e5eab3.png)

#### 参考資料

* [Github Actionsでテストや静的解析に失敗するプルリクエストをマージできないようにする - 千里霧中](https://goyoki.hatenablog.com/entry/2020/04/19/200021)

# おまけ

　リリースする前に少し確認したかったので、私は Actions で unitypackage を作りませんでしたが、以下のようなコマンドで作ることができます。

```bash
path/to/Unity/Editor.exe -projectPath path/to/your/project -batchmode -nographics -exportPackage "path/your/want/to/export" "path/to/export" -quit
```

　なお、`-exportPackage`の後の二つのパスは、`-projectPath`からの相対パスです。
　また、GitHub Actions でビルドしたければ [Builder - Game CI](https://game.ci/docs/github/builder) を使うといいと思います。私は使ってないので何も言えないですが。