C#でxUnitテスト備忘録

# はじめに
最近参加してるPJで初めてがっつりC#をかくことになりました。
その中でUnitテストもお願いね～と言われました。
今回は初めてなりにやってみた備忘録。

# 環境
- VisualStudio2019
    - ASP.NET Core

# xUnitテストの始め方

[こちら](https://qiita.com/takutoy/items/84fa6498f0726418825d)のサイトを参考に作っていきました。
書き方がまとまっていてわかりやすかったです。

# 今回やってみたこと備忘録
## データベースの値が正しく更新されているか確認したい…

- インメモリDBにテストデータを登録してテストすればいい

EntityFrameworkCoreで提供されているインメモリDBを使いました。
インメモリDBとはメモリをデータ保存領域とした、データベースプロバイダです。
先輩のコードをまねして作っていた私はどこにデータが登録されているのかわからず、
ずっと接続先の設定が悪いと思ってました。


実際にかいたコードは以下のとおり

```C#
using System;
using Xunit;
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();
        }


    }
```

テストコードはこちら。
内容は、データベースに登録したステータスコードが60に更新されるかを確認するものです。
テストしたいメソッドの返却値が更新対象のIDのみを返却するので、
そのIDをもとに再検索をかけて確認しています。


```C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;
using Newtonsoft.Json;
// テストしたいプロジェクトを参照するのを忘れずに

namespace Tests.Functions
{
        /// <summary>
        /// <see cref="Function{TDbContext}">のテストクラス
        /// </summary>
        public class FunctionTest : IClassFixture<MyDbContextFixture>, IDisposable
        {
            private readonly ITestOutputHelper _output;
            private readonly MyDbContextFixture _fixture;
            private readonly MyDBContextName _context;
            public FunctionTest(MyDbContextFixture fixture, ITestOutputHelper output)
            {
                _output = output;
                _fixture = fixture;
                _context = fixture.Context;
            }

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

        // DBに登録したいテストデータをいれます
        // GetTestData()
        
        /// <summary>
        /// テストデータを削除
        /// </summary>
        void IDisposable.Dispose()
        {
            var list = _context.PrPrint.ToList<PrPrint>();
            _context.PrPrint.RemoveRange(list);
            _context.SaveChanges();
        }


        /// <summary>
        /// ステータスコードが60から70に更新
        /// </summary>
        [Theory(DisplayName = "ステータスコード更新")]
        [MemberData(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);
            _output.WriteLine(JsonConvert.SerializeObject(result));
            var entity = _context.TestTable.Where(x => x.Id == result.Id).SingleOrDefault();
            // DBのステータスコードが70
            Assert.Equal("70", entity.StatusCd);
        }
    }
}
```

## 例外の種類とメッセージが正しいか確認したい…
- Assert.Throwsで例外情報を取得。その後に、Assert.Equalなどでメッセージとの整合性を確認。

```C#
        /// <summary>
        /// ステータスコードが69
        /// </summary>
        [Theory(DisplayName = "ステータスコード更新")]
        [MemberData(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>(() =>
            {
                function.Update_Test(inputModel);
            });
            Assert.IsType<ApplicationException>(ex);
            Assert.Equal("状態69であるデータの更新はできません", ex.Message);
        }
```

# やってみて
インメモリDBは割とテストに使えて便利だなと思いました。
今回初めてプロジェクト内でテストコードをがっつり書いたのですが、
テストコードを書くのに一苦労という感じでした。
でも、テストのデバック実行もできるので、今後使いこなしていきたいなという印象です。
今後また先輩から得た知識を備忘録として追記していく予定です。

# 参考
- [EntityFramework Core を使ってデータベースを読み書きするプログラムの単体テストに In-Memory データベースを使ってみた](https://devadjust.exblog.jp/26258587/)
- [xUnit.net でユニットテストを始める](https://qiita.com/takutoy/items/84fa6498f0726418825d)