やらなイカ?

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

Unity Test Frameworkの非同期テストで できること/ できないこと

Unity公式のユニットテストレームワークであるUnity Test Frameworkパッケージのバージョン1.3では、非同期テスト(以下Asyncテスト)がサポートされました。

改めて、できること/ できないことを確認してまとめました。

できること

非同期(async)メソッドの呼び出し

Test属性のテストにasyncキーワードを付与することで、テストメソッド内でasyncメソッドを呼び、その完了を待つことができます。

また、SetUpおよびTearDown属性も非同期メソッドに付与できます。 ただしUnitySetUp属性とは異なり、SetUp属性によるセットアップメソッドはドメインリロード*1の後に再実行されません。

サンプルコードなどは次の記事を参照してください。

www.nowsprinting.com

パラメタライズドテスト

次の属性はUnityTest属性と組み合わせて使用できませんでしたが、Asyncテストでは使用できます。

  • TestCase属性
  • TestCaseSource属性
  • Pairwise属性
  • Sequential属性

これら属性の使いかたについては『Unity Test Framework完全攻略ガイド』の第8章「パラメタライズドテスト」を参照してください。

www.nowsprinting.com

できないこと

以下は、Unity Test Framework v1.3.2時点での制限事項です。いずれもバグレポート済みで、修正されたら本記事にも反映する予定です。

[2/24追記] Issue Trackerに登録されています(UUM-25085)。 すでにお困りの方も、今はそうでないが将来お困りになる方も、ぜひvoteをお願いします!

併用するとテストが終了しない属性

次の属性を付けたAsyncテストメソッドは終了しなくなります。

  • MaxTime属性
  • Repeat属性
  • Retry属性

Throws制約による例外の検証

次のようにThrows制約を使用した例外の検証にasyncメソッドを指定すると、テストが終了しなくなります。

[Test]
public async Task 非同期メソッドの例外捕捉に制約モデルは使用できない()
{
    Assert.That(
        async () => await ThrowNewExceptionInMethod(),
        Throws.TypeOf<ArgumentException>()
        .And.Message.EqualTo("message!"));
}

クラシックモデルAPIThrowsAsyncも同様です。[11/18訂正]

[Test]
public async Task 非同期メソッドの例外捕捉をThrowsAsyncで行なう例()
{
    Assert.ThrowsAsync<ArgumentException>(
        async () => await ThrowNewExceptionInMethod());
}

今のところ、try-catchで書くしかありません。

[Test]
public async Task 非同期メソッドの例外捕捉をTryCatchで行なう例()
{
    try
    {
        await ThrowNewExceptionInMethod();
        Assert.Fail("例外が出ることを期待しているのでテスト失敗とする");
    }
    catch (ArgumentException expectedException)
    {
        Assert.That(expectedException.Message, Is.EqualTo("message!"));
    }
}

タイムアウトが機能しない

デフォルトではテストは3分でタイムアウトし失敗扱いとなりますが、Asyncテストではこれが機能しません。 Timeout属性で時間を指定しても同様です。

タイムアウトの問題はUnity Test Framework v1.3.4で修正されました

WebGLプレイヤーでTask.Delayが終了しない

Play ModeテストをWebGLプレイヤーで実行するとき、await Task.Delay()を引数1以上で呼び出しているとそのテストは終了しなくなります。 async SetUp/TearDownでも同様です。

await UniTask.Delay()は動作しますので、本事象はUniTaskを使用することで回避できます。

Edit ModeテストではTask.Delayが無効

これはそもそもEdit ModeテストがPlayerLoopで動いていないためで、yield returnステートメントにWaitForSecondsなどが指定できないのと同理由と考えられます。

*1:Edit Modeテストでyield return new RecompileScripts()などを実行したときに発生します。詳しくは『Unity Test Framework完全攻略ガイド』の3.3「Edit Modeテスト固有のyield instructions」を参照してください