【NUnit】テストケースを複数作る方法をまとめてみた

NUnit では、一つのテストメソッド内で複数テストケースを作ることができます。
そのための二つの属性の使い方をまとめてみました。
# TestCase
## 基本形
TestCase 属性内に、メソッドに渡す引数を書きます。
TestCase のパターン分テストを実行してくれます。

```C#
using NUnit.Framework;

public class Calculator
{
    public int AddTwoNumbers(int x, int y)
    {
        return x + y;
    }
}

[TestFixture]
public class CalculatorTest
{
    private Calculator _calculator;

    [SetUp]
    public void SetUp()
    {
        _calculator = new Calculator();
    }

    [TestCase(4, 2, 6)]
    [TestCase(9, 3, 12)]
    [TestCase(12, 3, 15)]
    public void AddTwoNumbers_ReturnTotal(int x, int y, int expected)
    {
        var result = _calculator.AddTwoNumbers(x, y);
        Assert.AreEqual(result, expected);
    }
}
```
## 名前付きパラメータ ExpectedResult
テストメソッド内で判定したい値を return させて使います。
属性内で期待結果を明示できるので、わかりやすいです。

```C#
using NUnit.Framework;

public class Calculator
{
    public int AddTwoNumbers(int x, int y)
    {
        return x + y;
    }
}

[TestFixture]
public class CalculatorTest
{
    private Calculator _calculator;

    [SetUp]
    public void SetUp()
    {
        _calculator = new Calculator();
    }

    [TestCase(4, 2, ExpectedResult=6)]
    [TestCase(9, 3, ExpectedResult = 12)]
    [TestCase(12, 3, ExpectedResult = 15)]
    public int AddTwoNumbers_ReturnTotal(int x, int y)
    {
        var result = _calculator.AddTwoNumbers(x, y);
        return result;
    }
}
```

# TestCaseSource
## 基本形
テストケースが多くなると、切り分けて管理したくなります。
そんなとき使えるのが、TestCaseSource 属性です。
なお、テストケースを生成するオブジェクトはプロパティや他クラス内のメソッドでも可能ですが、必ず static でなければなりません。

```C#
using NUnit.Framework;

public class Calculator
{
    public int AddTwoNumbers(int x, int y)
    {
        return x + y;
    }
}

[TestFixture]
public class CalculatorTest
{
    private Calculator _calculator;

    [SetUp]
    public void SetUp()
    {
        _calculator = new Calculator();
    }

    [TestCaseSource(nameof(AddNumbersCases))]
    public void AddTwoNumbers_ReturnTotal(int x, int y, int expected)
    {
        var result = _calculator.AddTwoNumbers(x, y);
        Assert.AreEqual(result, expected);
    }

    static object[] AddNumbersCases =
    {
        new object[] { 4, 2, 6 },
        new object[] { 9, 3, 12 },
        new object[] { 12, 3, 15 }
    };
}
```
## テストケース生成をイテレーターとして定義する
テストケースをイテレーターで定義することもできます。
ケースをメソッドごとに出し分けすることが可能になります。

```C#
using System.Collections.Generic;
using NUnit.Framework;

public class MyTestClass
{
    // TestStrings の generateLongTestCase = True
    [TestCaseSource(nameof(TestStrings), new object[] { true })]
    public void LongNameWithEvenNumberOfCharacters(string name)
    {
        Assert.That(name.Length, Is.GreaterThan(5));
        bool hasEvenNumOfCharacters = (name.Length / 2) == 0;
    }

    // TestStrings の generateLongTestCase = False
    [TestCaseSource(nameof(TestStrings), new object[] { false })]
    public void ShortName(string name)
    {
        Assert.That(name.Length, Is.LessThan(15));
    }

    // テストケースを生成
    // 出し分けの判定のための引数を持つ
    static IEnumerable<string> TestStrings(bool generateLongTestCase)
    {
        if (generateLongTestCase)
            // LongNameWithEvenNumberOfCharacters にのみ引数 name として渡される
            yield return "ThisIsAVeryLongNameThisIsAVeryLongName";
        yield return "SomeName";
        yield return "YetAnotherName";
    }
}
```
# 参照

- https://docs.nunit.org/articles/nunit/writing-tests/attributes/testcase.html
- https://docs.nunit.org/articles/nunit/writing-tests/attributes/testcasesource.html