以前、「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 }, }; }
日本語情報
以下がまとまっていて、参考になりました。