対象とするクラスにTestClass属性を、メソッドにTestMethod属性を指定します。
public class MyClass
{
static public int Method()
{
return 0;
}
}
[TestClass]
public class UnitTest
{
[TestMethod]
public void TestMethod1
{
int a = MyClass.Method();
Assert.AreEqual(1, a);
// Assert.AreEqual に失敗しました。<1> が必要ですが、<0> が指定されました。
}
}
クラス | テスト対象 |
---|---|
Assert | 一般 |
CollectionAssert | コレクション |
StringAssert | 文字列 |
AssertFailedException | 例外 |
AssertInconclusiveException | |
UnitTestAssertException |
属性 | 意味 |
---|---|
TestClassAttribute | このクラスは、テスト対象である |
TestMethodAttribute | このメソッドは、テスト対象である |
ExpectedExceptionAttribute | このテストから例外が投げられることが期待される |
IgnoreAttribute | このテストは一時的に無視される |
︙ |
テスト対象とするメソッドは、以下の条件を満たす必要があります。
この条件を満たすメソッドは、次のような形式となります。
[TestMethod] public void TestMethod() { }
メソッドがasyncでマークされていると、.NETのバージョンなどによってはテスト対象と認識されないことがあります。Asynchronous unit tests with .NET 4.0 - Stack Overflow
[TestMethod] public async void TestMethod() { await Task.Delay(1); }
よってTaskを返すメソッドもasyncで非同期とせず、同期で処理します。
[TestMethod] public void TestMethod() { Task.Delay(1).Wait(); }
ただしテストのスレッドで待機させると問題がある場合には、この方法は使えません。
一般的なオブジェクトをテストできます。
検証内容 | メソッド | |
---|---|---|
肯定 | 否定 | |
同一の値であるか | AreEqual() | AreNotEqual() |
同一のオブジェクトであるか | AreSame() | AreNotSame() |
指定の型であるか | IsInstanceOfType() | IsNotInstanceOfType() |
trueであるか | IsTrue() | IsFlase() |
nullであるか | IsNull() | IsNotNull() |
このAssertクラスは、DebugクラスのAssert()メソッドとは異なります。
コレクションの検証にはCollectionAssert、文字列の特殊な検証にはStringAssertを用います。
Assert.AreEqual メソッド (Microsoft.VisualStudio.TestTools.UnitTesting) | MSDNにあるように、多数のオーバーロードがあります。
public static void AreEqual( Object expected, // テストで予期するオブジェクト Object actual // テストで生成したオブジェクト )Assert.AreEqual メソッド (Object, Object) (Microsoft.VisualStudio.TestTools.UnitTesting) | MSDN
浮動小数点数は演算時に丸めによって誤差が生じるため、精度を指定できるAreEqual(Double, Double, Double)の形式で検証します。
public static void AreEqual<T>( T expected, // テストで予期するジェネリック型データ T actual // テストで生成したジェネリック型データ )Assert.AreEqual(T) メソッド (T, T) (Microsoft.VisualStudio.TestTools.UnitTesting) | MSDN
public static void AreEqual( double expected, // テストで予期する値 double actual, // テストで生成した値 double delta // 精度 )Assert.AreEqual メソッド (Double, Double, Double) (Microsoft.VisualStudio.TestTools.UnitTesting) | MSDN
public static void AreEqual( string expected, // テストで予期する値 string actual, // テストで生成した値 bool ignoreCase // trueならば、大文字/小文字を区別しない )Assert.AreEqual メソッド (String, String, Boolean) (Microsoft.VisualStudio.TestTools.UnitTesting) | MSDN
このメソッドは引数にZERO WIDTH NO-BREAK SPACEのような特殊文字を含むとき、第3引数を指定しないメソッドとは異なる結果を返します。
string str1 = new String(new char[] { 'A' }); string str2 = new String(new char[] { 'A', '\uFEFF' }); // U+FEFF (ZERO WIDTH NO-BREAK SPACE) Assert.AreEqual("A", str1, false); // 成功 Assert.AreEqual("A", str2, false); // 成功 Assert.AreEqual("A", str1); // 成功 Assert.AreEqual("A", str2); // Assert.AreEqual に失敗しました。<A> が必要ですが、<A> が指定されました。
コレクションをテストできます。
検証内容 | メソッド | |
---|---|---|
肯定 | 否定 | |
同一であるか (同じ値の要素が同じ順番で同じ数ある) | AreEqual() | AreNotEqual() |
等価であるか (同じ値の要素が同じ数ある) | AreEquivalent() | AreNotEquivalent() |
指定の要素を含むか | Contains() | DoesNotContain() |
別のコレクションのサブセット (部分集合) であるか | IsSubsetOf() | IsNotSubsetOf() |
検証内容 | メソッド |
---|---|
すべての要素が指定の型であるか | AllItemsAreInstancesOfType() |
すべての要素がnullでないか | AllItemsAreNotNull() |
すべての要素が一意であるか (同一の要素がない) | AllItemsAreUnique() |
public static void AreEqual ( System.Collections.ICollection expected, System.Collections.ICollection actual );AreEqual(ICollection, ICollection) - CollectionAssert.AreEqual Method (Microsoft.VisualStudio.TestTools.UnitTesting) | Microsoft Learn
int[] actual = Method(); int[] expected = new int[]{ 1, 2, 3 }; CollectionAssert.AreEqual(expected, actual);
複雑なコレクションは、IComparerを引数に取るメソッドで検証します。
public static void AreEqual ( System.Collections.ICollection expected, System.Collections.ICollection actual, System.Collections.IComparer comparer );
この場合には比較用に、IComparerを実装したクラスを用意します。
public class MyComparer : IComparer { int IComparer.Compare(Object x, Object y) { return (x == y) ? 0 : 1; } }
コレクションにnullの要素があるか、コレクションがnullのときに失敗します。
object[] c1 = new[] { new object(), new object() }; CollectionAssert.AllItemsAreNotNull(c1); // ok object[] c2 = new[] { new object(), null }; CollectionAssert.AllItemsAreNotNull(c2); // Collectionassert.AllItemsAreNotNull に失敗しました。 object[] c3 = null; CollectionAssert.AllItemsAreNotNull(c3); // CollectionAssert.AllItemsAreNotNull に失敗しました。パラメーター 'collection' は無効です。値を null にすることはできません。。
文字列をテストできます。これは次に示すように多様な条件で文字列を評価できるクラスであり、単純に等しいかどうか検証するだけならば、AssertクラスのAreEqual()を用います。
検証方法 | メソッド | |
---|---|---|
肯定 | 否定 | |
指定の正規表現に一致するか | Matches() | DoesNotMatch() |
検証方法 | メソッド |
---|---|
指定の文字列を含むか | Contains() |
指定の文字列で始まるか | StartsWith() |
指定の文字列で終わるか | EndsWith() |
public static void Contains ( string value, // substringを含むことが予期される文字列 string substring // value内に現れることが予期される文字列 );Contains(String, String) - StringAssert.Contains Method (Microsoft.VisualStudio.TestTools.UnitTesting) | Microsoft Learn
valueにはテストで生成した値を、substringにはテストの結果として予期する値を指定します。これはAreEqual()などの引数とは順が異なるため注意が必要です。
public static void StartsWith ( string value, // substringで始まることが予期される文字列 string substring // valueの接頭辞として予期される文字列 );StartsWith(String, String) - StringAssert.StartsWith Method (Microsoft.VisualStudio.TestTools.UnitTesting) | Microsoft Learn
例外の検証には、ExpectedExceptionAttributeを属性に指定します。ExpectedExceptionAttribute クラス (Microsoft.VisualStudio.TestTools.UnitTesting) | MSDN
この属性が付けられたメソッドでは、指定の例外が投げられないとテストに失敗します。
[TestMethod] [ExpectedException(typeof(System.Exception))] public void TestMethod1() { }
たとえばこの場合は、「テスト メソッド TestMethod1 は例外をスローしませんでした。」「テスト メソッドで定義されている属性 ExpectedExceptionAttribute で例外が予期されていました。」として失敗します。
[TestMethod] [ExpectedException(typeof(System.Exception))] public void TestMethod2() { throw new System.Exception(); }
一方で例外が投げられれば、テストに成功します。このとき例外はメソッドの外に投げられる必要があるため、メソッド内で捕捉しては失敗となります。
[TestMethod] [ExpectedException(typeof(System.Exception))] public void TestMethod3() { try { throw new System.Exception(); } catch (Exception) { } }
また例外が投げられることを期待する処理は、テストメソッドの最後にします。さもなくばそれ以降の処理が評価されないまま、テストに成功してしまうことになります。
[TestMethod]
[ExpectedException(typeof(System.Exception))]
public void TestMethod2()
{
throw new System.Exception();
Assert.Fail(); // ここが評価されないまま、テストに成功する
}
指定の例外から派生している型も含めるならば、AllowDerivedTypesプロパティをtrueとします。ExpectedExceptionAttribute.AllowDerivedTypes Property (Microsoft.VisualStudio.TestTools.UnitTesting) | Microsoft Learn
[ExpectedException(typeof(System.Exception), AllowDerivedTypes = true)]
Ignore属性をテストメソッドに追加することで、そのテストを一時的に無効にできます。
[TestMethod] [Ignore] public void TestMethod1() { }IgnoreAttribute クラス (Microsoft.VisualStudio.TestTools.UnitTesting) | MSDN
無効化したテストを再び有効にするには、Ignore属性を削除するか、コメントアウトします。方法 : テストを無効または有効にする | MSDN
TestMethod属性を削除することでもテストを無効にできますが、それではテストの存在そのものが隠されてしまうため、Ignore属性を用いるようにします。
複数テストの有効・無効を一括して切り替えるには、#ifディレクティブでIgnore属性の指定を制御するか、TestCategory属性でテストをまとめます。c# - Ignore IgnoreAttribute - Stack Overflow
テスト対象に共通の名前を付加することで、それらをグループ化して一括して選択できます。TestCategoryAttribute Class (Microsoft.VisualStudio.TestTools.UnitTesting) | Microsoft Learn
[TestMethod] [TestCategory("CategoryName")] public void TestMethod1() { }
この指定に対して、Visual StudioではTrait:"CategoryName"
のようにフィルタを指定することで、CategoryNameだけのテストを抽出できます。
テストに優先順位を付けることができます。PriorityAttribute Class (Microsoft.VisualStudio.TestTools.UnitTesting) | Microsoft Learn
これは順序指定テスト (ordered test) や、順位によるフィルタとして利用できます。What is PriorityAttribute Used for in MSTEST / Visual Studio - Stack Overflow
下表の属性を付加することで、テストに共通して必要な処理を行うメソッドを定義できます。
属性 | 適用回数 | 適用条件 | 実行時機 |
---|---|---|---|
AssemblyInitializeAttribute | アセンブリ内で1つだけ | staticメソッドで、TestContextを引数にとる | アセンブリのすべてのクラスの読み込み前 |
ClassInitializeAttribute | クラス内で1つだけ | クラスのすべてのテストメソッドの読み込み前 | |
TestInitializeAttribute | 制限なし | なし | クラスのテストメソッドの読み込み前 |
TestCleanupAttribute | クラスのテストメソッドの実行後 | ||
ClassCleanupAttribute | クラス内で1つだけ | staticメソッド | クラスのすべてのテストメソッドの実行後 |
AssemblyCleanupAttribute | アセンブリ内で1つだけ | アセンブリのすべてのクラスの実行後 |
たとえば1つのクラス内にテスト対象のメソッドが2つあるとき、これらの属性を付加したメソッドは次の順で呼ばれます。
[AssemblyInitialize] public static void AssemblyInit(TestContext context) { }AssemblyInitializeAttribute Class (Microsoft.VisualStudio.TestTools.UnitTesting) | Microsoft Learn
アプリケーションを開始した実行可能ファイルのパスから、テストから実行されたことを検出できます。
if (Application.StartupPath.EndsWith("TESTWINDOW")) { // テストから実行された }
Debugger.IsAttachedで、[テストのデバッグ]で実行されていることを検出できます。
テストの終了後にSystem.InvalidOperationExceptionが投げられ、「進行中のテストの実行がないので、テストの実行を取り消すことができません。(The cancelation of the test run is not possible as there is no test run which is in progress.)」と報告されることがあります。これはデバッグの設定で[マイ コードのみを有効にする]を有効にすることで解決できます。visual studio 2012 - Unit Test: The cancelation of the test run is not possible as there is no test run which is in progress - Stack Overflow
Visual Studioでテストをデバッグ実行したときにFormが表示されないときは、FormのShowInTaskbarをfalseに設定します。winforms - Displaying Windows Forms inside unit test methods - Stack Overflow
Form form = new Form(); if (System.Diagnostics.Debugger.IsAttached) { form.ShowInTaskbar = false; } form.ShowDialog();