はじめに
先月から部署が少々異動になりました。そこで、これまでは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)にキレイに一覧化されていました。
これをみればバッチリ!
テストする内容
数字を文字列で返すというとても単純なコードを書いたので、こちらをテストします。
using System;
namespace UnitTestDemo
{
public class UnitTest
{
public string NumTest(int i)
{
return i.ToString();
}
}
}
xUnitテストで試す
以前(C#でxUnitテスト備忘録)実践してるので、細かい部分ははしょります。
プロジェクトの作成
ファイル → 追加 → 新しいプロジェクトからxUnitテストプロジェクトを選択
テストコードをかく
プロジェクト参照を追加します。テストしたいプロジェクトを選択します。
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テストと同じ)
NuGetパッケージマネージャーから以下2つをインストールすることで、クラスライブラリをテストプロジェクトにすることもできました。
- NUnit
- NUnit3TestAdapter
ちなみにNUnit3TestAdapterは、VisualStudio等のテスト実行時に使用されるものみたいです。
テストコードをかく
プロジェクト参照を追加します。テストしたいプロジェクトを選択します。(xUnitと同じ)
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テスト備忘録)の記事でかいてみたことをNUnitに変えてみました。
インメモリDBを使うときのNUnit
データベース側の設定を書いたクラス。xUnitのときと変わりなし。
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]に変わることをおさえておけば大丈夫そう。
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の書き方とかが変わったくらいの変化。
(非同期のファンクションで試してます。)
/// <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));
}
まとめ
ちょっとした書き方が違うだけなので、テストを書く上でそこまで困ることはなさそう!