xUnitテストとNUnitテストを比較してみた備忘録

# はじめに
先月から部署が少々異動になりました。そこで、これまではxUnitテストを使用していたのですが、異動後の部署はNUnitテストを使用しているとのことだったので、違いやら書き方やらがちょっと気になり調べてみました。その備忘録。社内のすーぱーすごい先輩の勉強会の内容もメモ。

# 環境
- Windows10
- Visual Studio 2019 Professional
- ASP.Net Core

# これをおさえとけばなんとか書けそうな2つのテストの違い

|  xUnit  |  NUnit  | 補足 |
| ---- | ---- | ---- |
|  コンストラクタに記載  |  SetUp  | 最初に実行したい処理をかく。DIとか |
|  Fact  |  Test  | 1つのテストの塊 |
| InlineData | TestCase | たくさんテストケース試したいとき用 |
| MemberData | TestCaseSource | 入力値が複雑なときに使う印象 |
| IDisposable.Dispose | Teardown | 最後に実行したい処理をかく。　|

ドキュメントとしては[こちら(Comparing xUnit.net to other frameworks)](https://xunit.net/docs/comparisons)にキレイに一覧化されていました。
これをみればバッチリ！

# テストする内容
数字を文字列で返すというとても単純なコードを書いたので、こちらをテストします。

```C#
using System;

namespace UnitTestDemo
{
    public class UnitTest
    {
        public string NumTest(int i)
        {
            return i.ToString();
        }
    }
}
```

# xUnitテストで試す
[以前(C#でxUnitテスト備忘録)](https://qiita.com/usomaru/items/4d8ca2f895e793054a9a)実践してるので、細かい部分ははしょります。
## プロジェクトの作成

ファイル → 追加 → 新しいプロジェクトからxUnitテストプロジェクトを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201826/4f698fd1-1630-d829-3d8e-204f1149e9b3.png)

## テストコードをかく

プロジェクト参照を追加します。テストしたいプロジェクトを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201826/a0b208e1-4255-7a67-59b6-c87f7417c35d.png)


```C#
using System;
using UnitTestDemo;
using Xunit;

namespace XUnitTestDemo
{
    public class xUnitTestTest
    {
        private UnitTest _unitTest;

        public xUnitTestTest()
        {
            _unitTest = new UnitTest();
        }

        [Theory]
        [InlineData(1, "1")]
        public void Test1(int num, string strAns)
        {
            var result = _unitTest.NumTest(num);
            Assert.Equal(strAns, result);
        }
    }
}
```

# NUnitテストで試す
## テストプロジェクトの追加
ファイル → 追加 → 新しいプロジェクトからNUnitテストプロジェクトを選択
(この辺はxUnitテストと同じ)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201826/bd2d3d13-eb0a-a51a-4099-cf1a494df47e.png)

NuGetパッケージマネージャーから以下2つをインストールすることで、クラスライブラリをテストプロジェクトにすることもできました。

- NUnit
- NUnit3TestAdapter

ちなみにNUnit3TestAdapterは、VisualStudio等のテスト実行時に使用されるものみたいです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201826/8499af82-ab1c-593c-ea62-178471bbf158.png)


## テストコードをかく

プロジェクト参照を追加します。テストしたいプロジェクトを選択します。(xUnitと同じ)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201826/0af0c753-1e29-ec31-13bf-23df6822444f.png)

```C#
using NUnit.Framework;
using UnitTestDemo;

namespace NUnitTestDemo
{
    [TestFixture]
    public class Tests
    {
        private UnitTest _unitTest;

        [SetUp]
        public void Setup()
        {
            _unitTest = new UnitTest();
        }

        [TestCase(1, "1")]
        public void Test1(int num, string strAns)
        {
            var result = _unitTest.NumTest(num);
            Assert.That(strAns, Is.EqualTo(result));
        }
    }
}
```

①TestFixture → テストメソッドを含むClassをマークするのに使用
②SetUp → テストメソッド実行前に呼ばれるメソッドをマーク
③TestCase → 同一のテストメソッドで値違いなどケースが違う場合に使用
④Assert.That → NUnitテストでのアサーション。Is.EqualToすることで同値テストができる

# 以前xUnitで試したことをNUnitでかいてみる

[こちら(C#でxUnitテスト備忘録)](https://qiita.com/usomaru/items/4d8ca2f895e793054a9a)の記事でかいてみたことをNUnitに変えてみました。

## インメモリDBを使うときのNUnit

データベース側の設定を書いたクラス。xUnitのときと変わりなし。

```C#:MyDbContextFixture
using System;
using Microsoft.EntityFrameworkCore;

namespace Tests
{
    public class MyDbContextFixture : IDisposable
    {
        public DbContextOptions<MyDBContextName> Options;
        public MyDBContextName Context;

        public MyDbContextFixture ()
        {
            Options = new DbContextOptionsBuilder<MyDBContextName>()
                .UseInMemoryDatabase(databaseName: "MyDatabaseName")
                .Options;
            Context = new MyDBContextName(Options);
        }
        public void Dispose()
        {
            Context.Dispose();
        }


    }
```
テストコード。NUnitではIClassFixtureが[OneTimeSetUp]に、Disposeが[TearDown]に変わることをおさえておけば大丈夫そう。

```C#:NUnitTest
using Microsoft.EntityFrameworkCore;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
// テストしたいプロジェクトを参照するのを忘れずに

namespace Tests.Functions
{
        [TestFixture]
        public class NUnitTest
        {
            private MyDbContextFixture _fixture;
            private MyDBContextName _context;
            
        [OneTimeSetUp]
        public void OneTimeSetup()
        {
            _fixture = new MyDbContextFixture();
        }

        [SetUp]
        public void SetUp()
        {
            _context = _fixture.Context;
        }

        // ご自身で引数のテストデータ作成します

        // DBに登録したいテストデータをいれます
        // GetTestData()

        /// <summary>
        /// テストデータを削除
        /// </summary>
        [TearDown]
        public void TearDown()
        {
            var list = _context.PrPrint.ToList<PrPrint>();
            _context.PrPrint.RemoveRange(list);
            _context.SaveChanges();
        }


        /// <summary>
        /// ステータスコードが60から70に更新
        /// </summary>
        [TestCaseSource(nameof(MyTestDataName))]
        public void UpdateTest(inputModel)
        {
            var function = new TestFunction<MyDBContextName>(_context);
            // テストデータをInsert
            var list = GetTestData();
            _context.TestTable.AddRange(GetTestData());
            _context.SaveChanges();

            // テストしたい内容
            var result = function.Update_Test(inputModel);
            var entity = _context.TestTable.Where(x => x.Id == result.Id).SingleOrDefault();
            // DBのステータスコードが70
            Assert.That("70", Is.EqualTo(entity.StatusCd));
        }
    }
}
```

## 例外のときのNUnit

こちらはAssertionsの書き方とかが変わったくらいの変化。
(非同期のファンクションで試してます。)

```C#
        /// <summary>
        /// ステータスコードが69
        /// </summary>
        [TestCaseSource(nameof(MyTestDataName))]
        public void UpdateError(TestModel inputModel)
        {
            var function = new TestFunction<MyDBContextName>(_context);
            // テストデータをInsert
            var list = GetTestData();
            _context.PrPrint.AddRange(GetTestData());
            _context.SaveChanges();
            var ex = Assert.Throws<ApplicationException>(async() =>
                await function.Update_Test(inputModel));
            Assert.IsInstanceOf<ApplicationException>(ex);
            Assert.That("状態69であるデータの更新はできません", Is.EqualTo(ex.Message));
        }
```

# まとめ
ちょっとした書き方が違うだけなので、テストを書く上でそこまで困ることはなさそう！

# 参考
- [NUnit Documentation Site](https://docs.nunit.org/index.html)
- [Comparing xUnit.net to other frameworks](https://xunit.net/docs/comparisons)