NUnitでUnitTestする

もくじ
https://tera1707.com/entry/2022/02/06/144447#UnitTest

やりたいこと

WinUI3のexeの中のpublicなものをUnitTestしようと思うと、いつも使っていたMsTest(vstest.console.exe)でテスト実行がどうしてもできなかった。

で、代替を探していたら、NUnitというものを知った。
せっかくNUnitを使ったので、使い方をまとめておく。

前提

NUnit使い方

プロジェクトの追加で、C#の「NUnit テストプロジェクト」を追加する。

追加したプロジェクトの「UnitTest1.cs」に、テストコードを追加する。(ほかのcsファイルを追加して、そこに書いても当然OK)

NUnitで使うアトリビュート

つけるところ アトリビュート 説明
テストクラス [TestFixture] テスト対象のクラスにつける
[SetUpFixture] テスト全体の最初or最後に動くメソッド([OneTimeSetUp]or[OneTimeTearDown])を含むクラスにつける
テストメソッド [OneTimeSetUp] テストクラスの最初に一回だけ実行するテストメソッドにつける。
[SetUpFixture]がついたテストクラスの中にこれを書いた場合は、テスト全体の最初に一回だけ実行される。
[OneTimeTearDown] テストクラスの最後に一回だけ実行するテストメソッドにつける。
[SetUpFixture]がついたテストクラスの中にこれを書いた場合は、テスト全体の最後に一回だけ実行される。
[SetUp] 各テストメソッドの前に毎回実行されるメソッドにつける。
[TearDown] 各テストメソッドの後に毎回実行されるメソッドにつける。
[TestCase(1, "AAA")] テストメソッドに引数を渡して、同じテストロジックで複数テストを実行するためのメソッドにつける。
[TestCaseSource(nameof(Test4Args))] テストメソッドの引数として、変数を使う場合につける。

アトリビュートの具体例は下を参照。

NUnitひな型(部品どり)

using System.Diagnostics;

namespace TestProject
{
    [TestFixture]
    public class Tests
    {
        [OneTimeSetUp]
        public void OneTimeSetUp()
        {
            // テストクラスの最初に一回実施
            Debug.WriteLine("OneTimeSetUp");
        }

        [OneTimeTearDown]
        public void OneTimeTearDown()
        {
            // テストクラスの最後に一回実施
            Debug.WriteLine("OneTimeTearDown");
        }

        [SetUp]
        public void Setup()
        {
            // [Test]の前に毎回実施
            Debug.WriteLine("Setup");
        }

        [TearDown]
        public void TearDown()
        {
            // [Test]の後に毎回実施
            Debug.WriteLine("TearDown");
        }

        [Test]
        public void Test1()
        {
            Debug.WriteLine("Test1");
        }

        [Test]
        public void Test2()
        {
            Debug.WriteLine("Test2");
        }


        [TestCase(1, "AAA")]// ここの引数の数とメソッドの引数の数が一致していないとエラーにしてくれる
        [TestCase(2, "BBB")]
        public void Test3(int arg1, string arg2)
        {
            Debug.WriteLine($"Test3 {arg1}, {arg2}");
        }

        static object[] Test4Args =
        {
            new object[] { 10, "aaaaa"},
            new object[] { 20, "bbbbb"},
        };

        [TestCaseSource(nameof(Test4Args))]
        public void Test4(int arg1, string arg2)
        {
            Debug.WriteLine($"Test4 {arg1}, {arg2}");
        }
    }

    [TestFixture]
    public class Test2
    {
        [Test]
        public void Test1inTest2()
        {
            Debug.WriteLine("Test1inTest2");
        }
    }

    [SetUpFixture]
    public class TestSetupFixture
    {
        [OneTimeSetUp]
        public void RunBeforeAnyTests()
        {
            Debug.WriteLine("RunBeforeAnyTests");
        }

        [OneTimeTearDown]
        public void RunAfterAnyTests()
        {
            Debug.WriteLine("RunAfterAnyTests");
        }
    }
}

実行結果(どのアトリビュートを付けたらどういうタイミングで実行されるか、の参考に。)

RunBeforeAnyTests
Test1inTest2
OneTimeSetUp
Setup
Test1
TearDown
Setup
Test2
TearDown
Setup
Test3 1, AAA
TearDown
Setup
Test3 2, BBB
TearDown
Setup
Test4 10, aaaaa
TearDown
Setup
Test4 20, bbbbb
TearDown
OneTimeTearDown
RunAfterAnyTests

使ってみた感想

何となくだが、MSTestより、公式ページの説明がわかりやすい?気がする。
(自分が、今まで使ってたMSTestでのUTの経験値で呑み込みが早くなってただけかもだが、何となくそう感じた)

あとTestCaseを使ってるときに思ったが、[TestCase(1, "AAA")]に書いた引数とテストメソッドpublic void Test3(int arg1, string arg2)に書いた引数の型があってなかったらエラーが出てくれた。 たしか、MSTestだったらエラー出ずに実行時によくわからないエラーで怒られたような気がする。(記憶によるので、違ってるかも)

→何となく、NUnitの方が多少使いやすいかも?と感じた。
 開発環境の制約でNUnit使えない、とかが無ければ、NUnit使ってみようかなという気になった。

参考

NUnit公式。classやメソッドの頭につけるアトリビュート等はここに書いてある

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

MSDocsのNUnitページ

https://docs.microsoft.com/ja-jp/dotnet/core/testing/unit-testing-with-nunit