MSTestのアサーション
「打率計算」ではAssert.AreEqual<>()とAssert.Fail()しか使いませんでしたが、他にも便利なアサーションがありますので、主なものを紹介しておきます。(詳しくは、MSDNでMicrosoft.VisualStudio.TestTools.UnitTesting 名前空間を調べてください。)
| クラス | メソッド | 説明 |
Assert一般的なテスト |
AreEqual<T>(T expected, T actuial, string message) |
等しいかどうかテストする。失敗時にはmessageも出力される(省略可、以下同じ)。バリエーション: AreNotEqual<T>() |
AreEqual() |
AreEqual()には、非ジェネリックバージョンもある。浮動小数点の比較では精度指定ができる。バリエーション: AreNotEqual() |
|
AreSame(object expected, object actuial, string message) |
同一インスタンスかどうかテストする。 バリエーション: AreNotSame() |
|
Fail(string message) |
常に失敗させる。 | |
Inconclusive(string message) |
「このテストは不完全である」と示す。テストコードを自動生成させると、これが記述される。 | |
IsNull(object actual, string message) |
オブジェクトがnullかテストする。バリエーション: IsNotNull() |
|
IsTrue(bool condition, string message) |
条件式がtrueになるかテストする。バリエーション: IsFalse() |
|
CollectionAssertコレクションのテスト |
AllItemsAreNotNull(ICollection actuial, string message) |
すべての要素がnullではないことをテストする。 |
AllItemsAreUnique(ICollection actuial, string message) |
すべての要素がユニークであることをテストする。 | |
AreEqual(ICollection expected, ICollection actuial, IComparer comparer, string message) |
2つのコレクションが同一であることをテストする。要素の比較にはIComparerが使用される(省略可)。バリエーション: AreNotEqual() |
|
AreEquivalent(ICollection expected, ICollection actuial, string message) |
2つのコレクションが等価であることをテストする(順番は無視して、同じ要素が同じ数だけ入っているかどうか)。 | |
Contains(ICollection collection, object element, string message) |
コレクションに指定した要素が含まれていることをテストする。 バリエーション: DoesNotContain() |
|
IsSubsetOf(ICollection subset, ICollection superset, string message) |
最初のコレクションが2番目のコレクションのサブセットになっていることをテストする。 バリエーション: IsNotSubsetOf() |
|
StringAssert文字列のテスト |
Contains(string value, string substring, string message) |
最初の文字列に 2 番目の文字列が含まれていることをテストする。 |
Matches(string value, Regex pattern, string message) |
文字列が正規表現に一致することをテストする。 バリエーション: DoesNotMatch() |
|
StartsWith(string value, string substring, string message) |
文字列の先頭が、2番目の文字列で始まっていることをテストする。 バリエーション: EndWith() |
これは便利! Chaining Assertion for MSTest
最後に、MSTestでTDDするのが楽になるツールを紹介しましょう。@neuecc氏の「Chaining Assertion」です。
CodePlexで公開されています(下図、http://chainingassertion.codeplex.com/)ので、ダウンロードしてきたら、zipファイルの中からChainingAssertion.MSTest.csファイルをテストプロジェクトにコピーするだけで準備完了です。
パラメタライズドテスト
「お題その1」の初めの3つのテストケースは、「Chaining Assertion for MSTest」を使って、次のようにまとめて書けます。
using System; using Microsoft.VisualStudio.TestTools.UnitTesting; using Tddbc横浜; namespace Tddbc横浜Test { [TestClass()] public class 野球選手TestsChainingAssertion { private TestContext testContextInstance; public TestContext TestContext { get { return testContextInstance; } set { testContextInstance = value; } } [TestMethod()] [TestCase(1, 1, 0, 0.0, "<打数1,安打数0⇒打率0.0>")] [TestCase(2, 2, 1, 0.5, "<打数2,安打数1⇒打率0.5>")] [TestCase(10000, 10000, 5, 0.001, "<打数10000,安打数5⇒打率0.0005が四捨五入で0.001>")] public void Calc打率Test01_打率を計算() { TestContext.Run((int 打席数, int 打数, int 安打数, double 期待値, string msg) => { (new 野球選手()).Calc打率(打席数, 打数, 安打数).Is((decimal)期待値, msg); }); } } }
冒頭にあるTestContextのメンバー変数とプロパティは、「Chaining Assertion」のパラメタライズドテストのために必要です。これは単体テスト(基本単体テストではない方)を作れば、自動生成されます。
Assertクラスをやめて、「Chaining Assertion」の本来であるIs()を使うことには、好き嫌いがあるかもしれませんが、パラメタライズドテストだけでも使えます。NUnitと比べて少々不便なのは、パラメタライズドテストの個別のテストケースがテストビューなどに出てこないことくらいです。REDになったのがどのテストケースなのか分からなくなることがありますから、REDになったときに出力されるメッセージもパラメーターとして渡しています。
例外のテスト
例外が出ることを確認するテストケースは、「Chaining Assertion for MSTest」では次のように書けます。
[TestMethod()] public void Calc打率Test02_打数0のとき_ゼロ除算例外() { int 打席数 = 2; int 打数 = 0; int 安打数 = 0; 野球選手 p = new 野球選手(); var ex = AssertEx.Throws<DivideByZeroException>(() => p.Calc打率(打席数, 打数, 安打数) ); }
このコードでは、変数exには発生した例外を代入しているだけで使っていませんが、続けて例外のメッセージを検査したりすることも可能です。
まとめ
- (補足)Kent BeckによるTDDの定義
- (補足)実際の開発では全部TDDするわけではない
- MSTestとNUnitは一長一短
- MSTestでTDDするときも、進め方・考え方は同じ
- コードカバレッジは、「テストファーストしたはず」を自分でチェックするために使う
- MSTestには、CollectionやStringをテストするためのアサーションもある
- パラメタライズドテストや例外のテストは「Chaining Assertion」を使えば簡単

