やらなイカ?

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

Unity Test Framework v2.0ファーストインプレッション

Unity公式のユニットテストレームワークであるUnity Test Frameworkのバージョン2.0がプレリリースされたので早速触ってみました。 Unity 2022.2からデフォルトバージョンに採用される予定で、現在フォーラムでフィードバックを受け付けています

前提Unityバージョンは、v1のUnity 2019.2から少し上がり、Unity 2019.4になっていました。

アップグレード方法

プレリリースバージョンなので、デフォルトではPackage Managerには表示されません。 メニューから Edit | Project Settings... | Package Manager を開き、Enable Pre-release Packagesチェックボックスをonにすると、Package Managerでアップグレードできるようになります。

もしくはOpenUPM-CLIでバージョンを指定してインストールします。

$ openupm add com.unity.test-framework@2.0.1-pre.18

もしくは直接Packages/manifest.jsonの該当行を次のように書き換えます。

"com.unity.test-framework": "2.0.1-pre.18",

JetBrains Riderからのテスト実行は特に問題なさそうでしたが、何らかの問題が出る恐れもありますので、Riderを使う場合はできるだけRider Editorプラグインも最新版を使っていくほうがいいでしょう。

主要な新機能

Edit Mode/ Play Modeテストの結合

結合というより「相互乗り入れ可能」みたいなニュアンスです。Edit Mode/ Play Modeテストの概念が無くなったわけではありません。

具体的には、次のようになりました。

  • Edit Modeテストアセンブリ内のテストにRequiresPlayMode属性をつけると*1、Play Modeテストとして実行される
  • Play Modeテストアセンブリ内のテストにRequiresPlayMode(false)属性をつけると、Edit Modeテストとして実行される

従って、従来のEdit Mode/ Play Modeテストアセンブリはそのまま使えます。 その上で、今後は1アセンブリにEdit Mode/ Play Modeテストを詰め込むことも可能になった、ということです。

非同期テスト

v1.1では非同期処理のテストはUnityTest属性をつけたコルーチンしかサポートされていませんでした。 v2.0からは、次のようにTest属性のテストとしてasyncメソッドを呼び出すことができます。

[Test]
public async Task 非同期テストの例_Taskをawaitできる()
{
    await Foo(1);
    var actual = await Bar(2);
    Assert.That(actual, Is.EqualTo(3));
}

private static async Task Foo(int id)
{
    await Task.Delay(200);
}

private static async Task<int> Bar(int id)
{
    await Task.Delay(200);
    return id + 1;
}

もちろんUniTaskも使用できます。

[Test]
public async Task 非同期テストの例_UniTaskをawaitできる()
{
    await UniTaskFoo(1);
    var actual = await UniTaskBar(2);
    Assert.That(actual, Is.EqualTo(3));
}

private static async UniTask UniTaskFoo(int id)
{
    await UniTask.Delay(200);
}

private static async UniTask<int> UniTaskBar(int id)
{
    await UniTask.Delay(200);
    return id + 1;
}

v1.1でもUnityTest属性とUniTask.ToCoroutine()を組み合わせることでasync/awaitのテストは実現できましたが、UnityTest属性によるテストでは一部パラメタライズドテスト向けの属性の使用などに制約がありました。 その制限が無くなったことは、v2.0の最大のメリットと言えるでしょう。

[2023/1/28追記] Unity Test Framework v1.3で非同期テストが前倒し実装されました。詳しくは次の記事を参照してください。

www.nowsprinting.com

ParameterizedIgnore属性

パラメタライズドテスト向けのValues属性およびValueSource属性は指定したパラメーターの総当りで組み合わせが作られます。 v2.0で追加されたParameterizedIgnore属性を使用すると、実行したくない組み合わせをスキップできます。

次の場合、組み合わせは3x3=9通り作られますが、2件はスキップされ、実行されるのは7件になります*2

[Test]
[ParameterizedIgnore(Element.Fire, Element.Metal)]
[ParameterizedIgnore(Element.Water, Element.Earth)]
public void GetDamageMultiplier_ParameterizedIgnoreの使用例_指定した組み合わせはskipされる(
    [Values(Element.Wood, Element.Fire, Element.Water)] Element def,
    [Values(Element.None, Element.Earth, Element.Metal)] Element atk)
{
    var actual = def.GetDamageMultiplier(atk);
    Assert.That(actual, Is.EqualTo(1.0f));
}

Test Runnerウィンドウの変更

ボタンの位置などが変更されていますが、最も大きいのは、Edit Mode/ Play Modeの切り替えがチェックボックスに変わり、両方同時に指定できるようになったことでしょう*3

またカテゴリ指定の"Nothing"と"Everything"がなくなり、直感的な操作で指定できるようになりました*4

さらに、従来スタンドアロンプレイヤーでは実行するテストを選択できず、常に全件実行でしたが、v2.0では選択したテストのみスタンドアロンプレイヤーで実行できるようになりました。

その他の変更

使用できるNUnit3 APIなどにも変化があると思うのですが、未調査です。

サンプルコード

今回試したコードは、『Unity Test Framework完全攻略ガイド』サンプルコードのutf2ブランチに上げてあります。 このブランチをそのままマージすることはないと思いますが、ご参考になれば。

github.com

Unity Test Framework完全攻略ガイドの更新予定

『Unity Test Framework完全攻略ガイド』もv2.0への追随を予定しています*5。 名目上「第2版」に改版するつもりですが、現在販売している商品のアップデートで対応するつもりです。 (つまり、買い控えしなくて大丈夫です!)

www.nowsprinting.com

ただ、改版とは別に、Kindle版およびAmazon PODによるオンデマンド印刷版の発行を検討しています。 「Kindle版が欲しいがpdfと二重に購入したくない」という方は、もう少しお待ちいただいてもいいかもしれません。

参考

docs.unity3d.com

forum.unity.com

*1:Assembly, Class, Methodに付けられます。Assemblyに付けるのは本末転倒感がありますが

*2:組み合わせが減るわけではありません

*3:Edit Mode/ Play Mode混在の場合、すべてのEdit Modeテスト(RequiresPlayModeAttribute(false)も含む)を実行 → Enter Play Mode → すべてのPlay Modeテスト(RequiresPlayModeAttribute(true)も含む)を実行、の順に動作します

*4:Uncategorized(Category属性のついていないテストのみ)は健在

*5:以前からv1.2リリースの匂わせがあったので覚悟は完了していました