【Unity】Unity Test Runner(Test Framework)で複数の入力値を取り扱う方法まとめ

Unity Test Runnerで複数の入力値を取り扱う方法をまとめました。

Unity2020.2.3

複数の入力値を取り扱う?

例えばいま以下のように、1と3と9の三つの値をそれぞれ累乗した値が10以下であるかどうかをテストしたいとします。

using NUnit.Framework;

public class ExampleTest
{
    [Test]
    public void Test_1()
    {
        Test(1);
    }

    [Test]
    public void Test_3()
    {
        Test(3);
    }

    [Test]
    public void Test_9()
    {
        Test(9);
    }

    private void Test(int value)
    {
        Assert.That(value * value, Is.LessThanOrEqualTo(10));
    }
}

上記のように書いても以下のように正常にテストは作成できます。

f:id:halya_11:20210223223009p:plain
テスト

しかしテストしたい値毎にわざわざメソッドを定義するのはナンセンスです。
この記事ではこのようにテストにおいて複数の入力値を扱う方法についてまとめます。

Values

手軽に複数の値をテストするにはValuesアトリビュートが使えます。

複数の定数値を指定

Valuesアトリビュートを使うと複数の定数値を引数として指定できます。

using NUnit.Framework;

public class ExampleTest
{
    [Test]
    public void Test([Values(1, 3, 9)] int value)
    {
        Assert.That(value * value, Is.LessThanOrEqualTo(10));
    }
}

Test Runnerには以下のように表示されます。

f:id:halya_11:20210223223415p:plain
Values

Valuesを複数指定

Valuesアトリビュートは一つのメソッドに対して複数指定することができます。

[Test]
public void Test([Values(1, 3, 9)] int value, [Values("case1", "case2")] string text)

この場合、Valuesアトリビュートの組み合わせ分だけテストケースが生成されます。

f:id:halya_11:20210223223708p:plain
組み合わせ分のテストケース

Enumの全要素についてテスト

Valuesアトリビュートenum型の引数につけるとそのenumの全要素についてのテストを作成できます。

using NUnit.Framework;

public class ExampleTest
{
    [Test]
    public void Test([Values]ExampleEnum enumValue)
    {
    }
    
    public enum ExampleEnum
    {
        One,
        Two,
        Three
    }
}

f:id:halya_11:20210223223909p:plain
Enum分のテストケース

boolについてテスト

Valuesアトリビュートをbool型の引数につけるとtrue/falseそれぞれについてのテストを作成できます。

using NUnit.Framework;

public class ExampleTest
{
    [Test]
    public void Test([Values]bool boolValue)
    {
    }
}

f:id:halya_11:20210223224043p:plain
boolのテストケース

ValueSource

前節のValuesアトリビュートアトリビュートの中に直接テスト用の値を指定しました。
ValueSourceアトリビュートを使うと別途定義した値を指定できます。

フィールド・プロパティ・メソッドを指定できる

ValueSourceは以下のようにIEnumarableな引数の情報を持つstaticなフィールドの名前を与えることで使用します。

using NUnit.Framework;

public class ExampleTest
{
    [Test]
    public void Test([ValueSource(nameof(_values))]int value)
    {
    }

    private static int[] _values = {1, 3, 9};
}

結果は以下のようになります。

f:id:halya_11:20210223232843p:plain
テスト

また、フィールドの代わりにプロパティやメソッドを指定することもできます。

using System.Collections;
using NUnit.Framework;

public class ExampleTest
{
    // メソッドを指定
    [Test]
    public void Test([ValueSource(nameof(GetValues))]int value)
    {
    }

    private static IEnumerable GetValues()
    {
        yield return 1;
        yield return 3;
        yield return 9;
    }
}
他のクラスを指定

以下のように指定すると他のクラスで定義した値をテストの入力値にできます。

using System.Collections;
using NUnit.Framework;

public class ExampleTest
{
    // クラスの型、メソッド名の順に指定
    [Test]
    public void Test([ValueSource(typeof(Source), nameof(Source.GetValues))]int value)
    {
    }
}

public class Source
{
    public static IEnumerable GetValues()
    {
        yield return 1;
        yield return 3;
        yield return 9;
    }
}

TestCase

複数の値のテストにはTestCaseアトリビュートを使うこともできます。

使い方

TestCaseアトリビュートは以下のようにアトリビュートをテストケースの分だけ記述します。

using NUnit.Framework;

public class ExampleTest
{
    [TestCase(1, "foo")]
    [TestCase(3, "bar")]
    [TestCase(9, "baz")]
    public void Test(int value1, string value2)
    {
    }
}

結果は以下のようになります。

f:id:halya_11:20210223233944p:plain
テスト

ExpectedResultを使う

TestCaseアトリビュートの引数にExpectedResult引数を指定すると、テストメソッドの戻り値がその値であることをテストできます。

using NUnit.Framework;

public class ExampleTest
{
    [TestCase(1, 1, ExpectedResult = 1)]
    [TestCase(3, 2, ExpectedResult = 6)]
    [TestCase(9, 3, ExpectedResult = 27)]
    public int Test(int value1, int value2)
    {
        return value1 * value2;
    }
}

TestCaseSource

TestCaseSourceを使うとValueSourceのように別途定義した値をテストの引数として指定できます。

フィールド・プロパティ・メソッドを指定できる

TestCaseSourceは以下のようにして使います。

using NUnit.Framework;

public class ExampleTest
{
    [Test]
    [TestCaseSource(nameof(_values))]
    public void Test(int value)
    {
    }

    private static int[] _values = {1, 3, 9};
}

指定するフィールドはIEnumarableな引数の情報を持つstaticなものである必要があります。
ValueSource同様、フィールドの代わりにメソッドやプロパティも使えます。

他のクラスを指定

以下のように指定すると他のクラスで定義した値をテストの入力値にできます。

using System.Collections;
using NUnit.Framework;

public class ExampleTest
{
    // クラスの型、メソッド名の順に指定
    [Test]
    [TestCaseSource(typeof(Source), nameof(Source.GetValues))]
    public void Test(int value)
    {
    }
}

public class Source
{
    public static IEnumerable GetValues()
    {
        yield return 1;
        yield return 3;
        yield return 9;
    }
}
IEnumerableなクラスを指定

以下のようにIEnuemrableなクラスを指定することもできます。

using System.Collections;
using NUnit.Framework;

public class ExampleTest
{
    // IEnumerableクラスの型を指定
    [Test]
    [TestCaseSource(typeof(Source))]
    public void Test(int value)
    {
    }
}

public class Source : IEnumerable
{
    public IEnumerator GetEnumerator()
    {
        yield return 1;
        yield return 3;
        yield return 9;
    }
}

Range

Rangeアトリビュートを使うと指定した範囲の値を入力値として使えます。

使い方

Rangeアトリビュートは以下のように引数に対して使います。

using NUnit.Framework;

public class ExampleTest
{
    [Test]
    public void Test([Range(1, 3)]int value)
    {
    }
}

結果は以下のようになります。

f:id:halya_11:20210223235233p:plain
テスト

ステップを指定

また第三引数にステップ数を指定できます。
指定するとステップ数だけ値を飛ばして入力値を作成します。

using NUnit.Framework;

public class ExampleTest
{
    [Test]
    public void Test([Range(0, 100, 10)]int value)
    {
    }
}

f:id:halya_11:20210223235437p:plain
テスト

Random

Randomアトリビュートを使うと指定した範囲内の値を指定した数だけテストの入力値として指定します。

using NUnit.Framework;

public class ExampleTest
{
    [Test]
    public void Test([Random(0, 100, 5)]int value)
    {
    }
}

f:id:halya_11:20210223235644p:plain
テスト

UnityTestアトリビュートとの相性

Unity Test RunnerではIEnumeratorを返すメソッドにUnityTestアトリビュートを付けると複数フレームにまたがるテストが行えます。

using System.Collections;
using NUnit.Framework;
using UnityEngine.TestTools;

public class ExampleTest
{
    [UnityTest]
    public IEnumerator Test(int value)
    {
        yield return null;
        Assert.That(true);
        yield return null;
    }
}

このようなテストを書く場合、上記で紹介したアトリビュートの一部が使えないので注意する必要があります。
具体的には以下の表を参照してください。

アトリビュート Test UnityTest
Values
ValueSource
TestCase ×
TestCaseSource ×
Range
Random

ちなみにTestCaseやTestCaseSourceをUnityTestなメソッドにつけると以下のようにテストが失敗します。

f:id:halya_11:20210224000254p:plain
エラー

関連

light11.hatenadiary.com

参考

docs.nunit.org

docs.nunit.org