以前、「The Art of Unit Testing, Second Edition with examples in C# 」をxUnit.netで写経していた時に悩んだところなどを残しておきます。
環境
- xUnit.net 2.0.0
- VisualStudio 2013 Community
準備など
xUnit.net Runnerのインストール
「Instant Nancy」を写経した時以降にxUnit.netのバージョンが上がり、2.0.0
になりました。
その時は--pre
が必要でしたが、現在では正式バージョンになっているため、不要になっています。
本体やRunnerのインストールは、公式ページの「Getting Started with xUnit.net」を確認します。
Getting Started with xUnit.net > xUnit.net
プロジェクトを作るところからの流れ
忘れた時のためのメモです。
- テスト対象のプロジェクトを作る (
Hoge
) - テストプロジェクトをクラスライブラリとかで作る (
Hoge.Test
) - テストプロジェクトにて、NuGetで
xUnit.net
をインストールする - テストプロジェクト(Hoge.Test)にて、テスト対象プロジェクト(Hoge)を参照に追加する
- テストクラスにて、
using Xunit;
を使用の上、テストメソッドに[Fact]
を付ける - あとはテストを書いていく
すべてのテストを実行するショートカット
xUnit.netとはあまり関係ないですが、デフォルトでは、 Ctrl + R & Ctrl + A
です。
NUnitとの比較
xUnit.netのドキュメントに比較表があります。
xUnit.net - Unit testing framework for C# and .NET (a successor to NUnit) - Home
最終更新日が「Nov 14, 2012」となっているため、v2で廃止された[PropertyData]
などの古い情報が残っている場合もありますが、大きくは変わっていないので参考になります。
比較表の中でも写経をしていて気になったものを、以下に残しておきます。
テストにパラメータを渡す場合
[Theory]
+ [xxxData]
を使います。写経ではこんな感じです。
[Theory] [InlineData("filewithgoodextension.SLF")] [InlineData("filewithgoodextension.slf")] public void IsValidLogFileName_ValidExtensions_ReturnsTrue(string file) { bool result = analyzer.IsValidLogFileName(file); Assert.True(result); }
例外のテスト
NUnitでは[ExpectedException]
やAssert.Catch()
となりますが、xUnit.netでは、[Fact]
+ Assert.Throws()
を使います。写経ではこんな感じです。
[Fact] public void IsValidFileName_EmptyFileName_ThrowsException() { var exception = Assert.Throws<ArgumentException>( () => analyzer.IsValidLogFileName(string.Empty)); Assert.Equal("filename has to be provided", exception.Message); }
Stackoverflowはこちら。
mstest - Unit test exception messages with xUnit - Stack Overflow
なお、v2にてAssert.DoesNotThrow()
は削除されたようです。
Remove Assert.DoesNotThrow · Issue #188 · xunit/xunit
スキップするテスト
NUnitは[Ignore]
ですが、xUnit.netではFact(Skip = <reason>)
となります。写経ではこんな感じです。
[Fact(Skip = "Use `IsValidLogFileName_ValidExtensions_ReturnsTrue` method")] public void IsValidLogFileName_GoodExtensionLowercase_ReturnsTrue() { bool result = analyzer.IsValidLogFileName("filewithgoodextension.slf"); Assert.True(result); }
カテゴリ分け
NUnitの[Category]
と同じようなものはなさそうで、代替として[Trait(<key>, <value>)]
が挙げられていました。
Why I’m not migrating to xUnit completely « Trailmax Tech
写経ではこんな感じです。
[Fact] [Trait("category", "fast test")] // Categoryの代替案 public void IsValidFileName_BadExtension_ReturnsFalse() { var localAnalyzer = new LogAnalyzer(); bool result = localAnalyzer.IsValidLogFileName("filewithbadextension.foo"); Assert.False(result); }
なお、Traitを使うことで、VisualStudioのテストランナーのコンテキストメニューにてグループ化 > 特徴
を選ぶとカテゴリ的なもので分類されます。
xUnit.netのv1とv2で異なる部分
いくつかありますが、ここでも気になったものを残しておきます。
テスト結果を出力ウィンドウなどに出力する
v1のときはTrace.WriteLine
やDebug.WriteLine
が使えたようですが、v2より変更となり使えなくなりました。
Capturing Output > xUnit.net
v2では、ITestOutputHelper
型のオブジェクトをテストクラスのコンストラクタで受け取り、そのオブジェクトを使って出力します。写経ではこんな感じです。
public LogAnalyzerTests(Xunit.Abstractions.ITestOutputHelper output) { this.output = output; output.WriteLine("Setup"); // v2ではTraceやDebugは使えない System.Diagnostics.Trace.WriteLine("Trace Setup"); System.Diagnostics.Debug.WriteLine("Debug Setup"); }
経緯などは以下のIssueにまとまっていました。
- Add support for test output (for non-tests) · Issue #173 · xunit/xunit
- No stdout capture when running in Visual Studio as MS runner does · Issue #242 · xunit/xunit
[PropertyData]
の代わりの[MemberData]
xUnit.netのv2より[PropertyData]
が廃止されて[MemberData]
へとリネームされています。
Upgrading xunit.extensions > xUnit.net
MemberDataでは、staticなプロパティの他、staticメソッドやstaticフィールドが使えるようになりました。写経ではこんな感じです。
// xUnit.net v2から、PropertyDataがMemberDataへと変更 // 静的プロパティのほか、静的メソッドや静的メンバ変数も利用可能 [Theory] [MemberData("StaticPropertyTestData")] [MemberData("StaticMethodTestData")] public void IsValidLogFileName_ValidExtensions_ChecksThem(string file, bool expected) { bool result = analyzer.IsValidLogFileName(file); Assert.Equal(expected, result); } // MemberData用静的プロパティ public static IEnumerable<object> StaticPropertyTestData { get { return new[] { new object[] { "filewithgoodextension_property.SLF", true }, new object[] { "filewithgoodextension_property.slf", true }, new object[] { "filewithgoodextension_property.foo", false }, }; } } // MemberData用静的メンバ public static IEnumerable<object> StaticMethodTestData() { return new[] { new object[] { "filewithgoodextension_method.SLF", true }, new object[] { "filewithgoodextension_method.slf", true }, new object[] { "filewithgoodextension_method.foo", false }, }; }
日本語情報
以下がまとまっていて、参考になりました。