Chaining Assertion ver 1.6.0.0
- 2011-09-20
Chaining Assertionというメソッドチェーンスタイルでユニットテストを書くことの出来るテスト用補助ライブラリをver.1.6に更新しました。内容はAssertEx.ThrowsContractExceptionの追加と、ラムダ式を使った判定の失敗時メッセージが親切になりました。
ThrowsContractException
まず、契約失敗でスローされる例外を厳密に検出することができるということについて。以前に基礎からのCode Contractsというスライドに書きましたが、Contract.Requires(など)で発生する、契約の条件に合っていない時にスローされる例外は、ContractExceptionというリライト時にアセンブリに埋め込まれる型のため、型を判別してのcatchは不可能です。
そのため、従来は大雑把にExceptionがスローされるか否か、でしか判定できませんでした。そこでThrowsContractExceptionを使うと、厳密に、契約失敗の例外のみを判定することができます。
// こんなContractなクラスがあるとして
public class QB
{
public void Homu(string s)
{
Contract.Requires(s != null);
}
}
// こういう風に契約違反の例外を捉えることができる
[TestMethod]
public void QBTest()
{
AssertEx.ThrowsContractException(() =>
new QB().Homu(null));
}
Code Contractsを使ったコードを書いている場合は、便利に使えるのではないでしょうかー。
ラムダ式によるアサーション
で、Chaining Assertionって、こんな感じに書けます。
// こんなクラスがあるとして
public class Person
{
public int Age { get; set; }
public string FamilyName { get; set; }
public string GivenName { get; set; }
}
// こうして判定することが出来ます
[TestMethod]
public void PersonTest()
{
// GetPersonメソッドでPersonインスタンスを取得するとして、
// こんな風にメソッドチェーンで書ける(10歳以下でYamadaTarouであることをチェックしてます)
new HogeService().GetPerson().Is(p =>
p.Age <= 10 && p.FamilyName == "Yamada" && p.GivenName == "Tarou");
}
今回追加したのは、失敗した時のメッセージをより分かりやすくしました。
[TestMethod]
public void PersonTest()
{
// こんなPersonがあるとすると
var person = new Person { Age = 50, FamilyName = "Yamamoto", GivenName = "Tasuke" };
// このアサーションは失敗します
person.Is(p => p.Age <= 10 && p.FamilyName == "Yamada" && p.GivenName == "Tarou");
}
分かりやすいですよね!値は全部のダンプじゃなくて、ラムダ式の中で使われているプロパティ/フィールドのみを出すことにしているので、メッセージ欄が極度に爆発することもないです。今はまだ一階層の値しか出力してないのですが、いずれはもう少し複雑に解析して表示できるようにしたいところ。理想はGroovyのPowerAssertのようなグラフィカルな表示ですね。Expressionにより、データはあるので、解析をがんばれば作ること自体は可能だ、というのがC#のポテンシャルです。活かすか殺すかは、努力次第。まだ、活かしきれてはいません。
まとめ
MSでSilverlight周りのチームにいるJafar Husain氏(Silverlight Toolkitに入ってるという話で最初にRxを世界に紹介した人ですね!)は、unfold: Better Unit Tests with Test.Assert() for NUnit/VSTT/SUTFという記事で.NETはずっとパワフルなのに、いつまでJUnitスタイルの古いAPIを引きずってるんだ?と問題提起し、Expressionを解析して適切なAssertに差し替えるという、Queryable的な実装を示しました。Chaining Assertionでは、もっと野蛮に、拡張メソッドとラムダ式により、C#らしいスタイルで軽快に記述することを可能にしました。
最近少し刺され気味なので若干弁解しておきますが、別にスタイルは自由ですよ。でも他人に使わせるものは、より良いものであるべきだし、そうして他人が使ったりリファレンスとして参照されるものが、あんまりな出来だったら、そりゃ一言あって然りでしょう。本当に多くの人が参照するものだったら、なおのことです。いやまあ、度を超えた発言は刺されてもしょうがないですが。
NuGetからも入れられるのと、MSTestの他にNUnit, MbUnit, xUnit.NETにも対応しているので、試してもらえると嬉しいです。