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)); } }
上記のように書いても以下のように正常にテストは作成できます。
しかしテストしたい値毎にわざわざメソッドを定義するのはナンセンスです。
この記事ではこのようにテストにおいて複数の入力値を扱う方法についてまとめます。
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には以下のように表示されます。
Valuesを複数指定
Valuesアトリビュートは一つのメソッドに対して複数指定することができます。
[Test] public void Test([Values(1, 3, 9)] int value, [Values("case1", "case2")] string text)
この場合、Valuesアトリビュートの組み合わせ分だけテストケースが生成されます。
Enumの全要素についてテスト
Valuesアトリビュートをenum型の引数につけるとそのenumの全要素についてのテストを作成できます。
using NUnit.Framework; public class ExampleTest { [Test] public void Test([Values]ExampleEnum enumValue) { } public enum ExampleEnum { One, Two, Three } }
boolについてテスト
Valuesアトリビュートをbool型の引数につけるとtrue/falseそれぞれについてのテストを作成できます。
using NUnit.Framework; public class ExampleTest { [Test] public void Test([Values]bool boolValue) { } }
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}; }
結果は以下のようになります。
また、フィールドの代わりにプロパティやメソッドを指定することもできます。
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) { } }
結果は以下のようになります。
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) { } }
結果は以下のようになります。
ステップを指定
また第三引数にステップ数を指定できます。
指定するとステップ数だけ値を飛ばして入力値を作成します。
using NUnit.Framework; public class ExampleTest { [Test] public void Test([Range(0, 100, 10)]int value) { } }
Random
Randomアトリビュートを使うと指定した範囲内の値を指定した数だけテストの入力値として指定します。
using NUnit.Framework; public class ExampleTest { [Test] public void Test([Random(0, 100, 5)]int value) { } }
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なメソッドにつけると以下のようにテストが失敗します。