ジェネリック メソッドの単体テストUnit tests for Generic Methods

ジェネリック メソッドには、他のメソッドと同様に、単体テストを生成できます。詳細については、「方法: 単体テストを作成して実行する」を参照してください。You can generate unit tests for generic methods exactly as you do for other methods, as described in How to: Create and Run a Unit Test. 次のセクションでは、ジェネリック メソッドの単体テストの作成に関する情報と例を示します。The following sections provide information about and examples of creating unit tests for generic methods.

型引数と型制約Type Arguments and Type Constraints

Visual StudioVisual Studio で、MyList<T> など、ジェネリック クラスの単体テストが生成されると、ジェネリック ヘルパー メソッドとテスト メソッドの 2 つのメソッドが生成されます。When Visual StudioVisual Studio generates a unit test for a generic class, such as MyList<T>, it generates two methods: a generic helper and a test method. MyList<T> に 1 つ以上の型制約がある場合、型引数はすべての型制約を満たす必要があります。If MyList<T> has one or more type constraints, the type argument must satisfy all the type constraints. テスト対象のジェネリック コードが許容されたすべての入力に対して予想どおりに動作することを確認するには、テスト メソッドで、テストするすべての制約を指定して、ジェネリック ヘルパー メソッドを呼び出します。To make sure that the generic code under test works as expected for all permissible inputs, the test method calls the generic helper method with all the constraints that you want to test.

Examples

ジェネリックの単体テストの例を次に示します。The following examples illustrate unit tests for generics:

  • 生成されたテスト コードの編集Editing Generated Test Code. この例には、「生成後のテスト コード」と「編集後のテスト コード」という 2 つのセクションがあります。This example has two sections, Generated Test Code and Edited Test Code. ここでは、ジェネリック メソッドから生成される未加工のテスト コードを編集して有用なテスト メソッドにする方法を示します。It shows how to edit the raw test code that is generated from a generic method into a useful test method.

  • 型制約の使用Using a Type Constraint. この例では、型制約を使用するジェネリック メソッドの単体テストを示します。This example shows a unit test for a generic method that uses a type constraint. この例では、型制約が満たされていません。In this example, the type constraint is not satisfied.

例 1: 生成されたテスト コードの編集Example 1: Editing Generated Test Code

このセクションのテスト コードでは、SizeOfLinkedList() という名前のテスト対象コードのメソッドをテストします。The test code in this section tests a code-under-test method named SizeOfLinkedList(). このメソッドは、リンク リスト内のノード数を示す整数を返します。This method returns an integer that specifies the number of nodes in the linked list.

「生成後のテスト コード」にある最初のコード例では、Visual Studio Enterprise で生成された編集前のテスト コードを示しています。The first code sample, in the section Generated Test Code, shows the unedited test code as it was generated by Visual Studio Enterprise. 「編集後のテスト コード」にある 2 番目のコード例では、2 つのデータ型 intchar に対して SizeOfLinkedList メソッドの機能をテストする方法を示しています。The second sample, in the section Edited Test Code, shows how you could make it test the functioning of the SizeOfLinkedList method for two different data types, int and char.

このコードでは、2 つのメソッドを示します。This code illustrates two methods:

  • SizeOfLinkedListTestHelper<T>() テスト ヘルパー メソッド。a test helper method, SizeOfLinkedListTestHelper<T>(). 既定では、テスト ヘルパー メソッドは名前に "TestHelper" を使用しています。By default, a test helper method has "TestHelper" in its name.

  • SizeOfLinkedListTest() テスト メソッド。a test method, SizeOfLinkedListTest(). 各テスト メソッドは、TestMethod 属性でマークされています。Every test method is marked with the TestMethod attribute.

生成後のテスト コードGenerated Test Code

次のテスト コードは、SizeOfLinkedList() メソッドから生成されました。The following test code was generated from the SizeOfLinkedList() method. これは生成された編集前のテストであるため、SizeOfLinkedList メソッドを正しくテストするように変更する必要があります。Because this is the unedited generated test, it must be modified to correctly test the SizeOfLinkedList method.

public void SizeOfLinkedListTestHelper<T>()  
{  
    T val = default(T); // TODO: Initialize to an appropriate value  
    MyLinkedList<T> target = new MyLinkedList<T>(val); // TODO: Initialize to an appropriate value  
    int expected = 0; // TODO: Initialize to an appropriate value  
    int actual;  
    actual = target.SizeOfLinkedList();  
    Assert.AreEqual(expected, actual);  
    Assert.Inconclusive("Verify the correctness of this test method.");  
}  

[TestMethod()]  
public void SizeOfLinkedListTest()  
{  
   SizeOfLinkedListTestHelper<GenericParameterHelper>();  
}  

上記のコードのジェネリック型パラメーターは GenericParameterHelper です。In the preceding code, the generic type parameter is GenericParameterHelper. このパラメーターを編集して特定のデータ型を指定できますが、次の例で示すように、このステートメントを編集せずにテストを実行できます。Whereas you can edit it to supply specific data types, as shown in the following example, you could run the test without editing this statement.

編集後のテスト コードEdited Test Code

次のコードでは、テスト対象コードの SizeOfLinkedList() メソッドのテストが成功するように、テスト メソッドとテスト ヘルパー メソッドを編集しました。In the following code, the test method and the test helper method have been edited to make them successfully test the code-under-test method SizeOfLinkedList().

テスト ヘルパー メソッドTest Helper Method

テスト ヘルパー メソッドは、step 1 ~ 5 というラベルの付いたコード行に対応する、次の手順を実行します。The test helper method performs the following steps, which correspond to lines in the code labeled step 1 through step 5.

  1. ジェネリック リンク リストを作成します。Create a generic linked list.

  2. リンク リストに 4 つのノードを追加します。Append four nodes to the linked list. これらのノードの内容のデータ型は不明です。The data type of the contents of these nodes is unknown.

  3. リンク リストの予想サイズを expected 変数に割り当てます。Assign the expected size of the linked list to the variable expected.

  4. リンク リストの実際のサイズを計算し、actual 変数に割り当てます。Compute the actual size of the linked list and assign it to the variable actual.

  5. Assert ステートメントで、actualexpected を比較します。Compare actual with expected in an Assert statement. 実際のサイズが予想サイズと異なる場合、テストは失敗します。If the actual is not equal to the expected, the test fails.

テスト メソッドTest Method

テスト メソッドは、SizeOfLinkedListTest という名前のテストの実行時に呼び出されるコードにコンパイルされます。The test method is compiled into the code that is called when you run the test named SizeOfLinkedListTest. テスト メソッドは、step 6 と step 7 というラベルの付いたコード行に対応する、次の手順を実行します。It performs the following steps, which correspond to lines in the code labeled step 6 and step 7.

  1. テスト ヘルパー メソッドの呼び出し時に <int> を指定し、integer 変数に対してテストを実行できることを確認します。Specify <int> when you call the test helper method, to verify that the test works for integer variables.

  2. テスト ヘルパー メソッドの呼び出し時に <char> を指定し、char 変数に対してテストを実行できることを確認します。Specify <char> when you call the test helper method, to verify that the test works for char variables.


public void SizeOfLinkedListTestHelper<T>()  
{  
    T val = default(T);   
    MyLinkedList<T> target = new MyLinkedList<T>(val); // step 1  
    for (int i = 0; i < 4; i++) // step 2  
    {  
        MyLinkedList<T> newNode = new MyLinkedList<T>(val);  
        target.Append(newNode);  
    }  
    int expected = 5; // step 3  
    int actual;  
    actual = target.SizeOfLinkedList(); // step 4  
    Assert.AreEqual(expected, actual); // step 5  
}  

[TestMethod()]  
public void SizeOfLinkedListTest()   
{  
    SizeOfLinkedListTestHelper<int>();  // step 6  
    SizeOfLinkedListTestHelper<char>(); // step 7  
}  

注意

SizeOfLinkedListTest テストを実行するたびに、TestHelper メソッドは 2 回呼び出されます。Each time the SizeOfLinkedListTest test runs, its TestHelper method is called two times. テストを成功させるには、アサート ステートメントが毎回 true と評価される必要があります。The assert statement must evaluate to true every time for the test to pass. テストが失敗した場合、<int> を指定した呼び出しと <char> を指定した呼び出しのどちらが原因でテストが失敗したかはっきりしないことがあります。If the test fails, it might not be clear whether the call that specified <int> or the call that specified <char> caused it to fail. これをはっきりさせるには、コール スタックを調べるか、テスト メソッドにブレークポイントを設定してテスト実行時にデバッグします。To find the answer, you could examine the call stack, or you could set breakpoints in your test method and then debug while running the test. 詳細については、「方法 : ASP.NET ソリューションでのテスト中にデバッグする」を参照してください。For more information, see How to: Debug while Running a Test in an ASP.NET Solution.

例 2: 型制約の使用Example 2: Using a Type Constraint

この例では、満たされていない型制約を使用するジェネリック メソッドの単体テストを示します。This example shows a unit test for a generic method that uses a type constraint that is not satisfied. 最初のセクションでは、テスト対象コード プロジェクトのコードを示します。The first section shows code from the code-under-test project. 型制約が強調表示されています。The type constraint is highlighted.

2 番目のセクションでは、テスト プロジェクトのコードを示します。The second section shows code from the test project.

テスト対象コード プロジェクトCode-Under-Test Project

using System;  
using System.Linq;  
using System.Collections.Generic;  
using System.Text;  

namespace ClassLibrary2  
{  
    public class Employee  
    {  
        public Employee(string s, int i)  
        {  
        }  
    }  

    public class GenericList<T> where T : Employee  
    {  
        private class Node  
        {  
            private T data;  
            public T Data  
            {  
                get { return data; }  
                set { data = value; }  
            }  
        }  
    }  
}  

テスト プロジェクトTest Project

新しく生成された単体テストと同様に、有効な結果を返すように、不確定ではない Assert ステートメントをこの単体テストに追加する必要があります。As with all newly generated unit tests, you must add non-inconclusive Assert statements to this unit test to make it return useful results. これらのステートメントは、TestMethod 属性でマークされているメソッドではなく、このテストでは DataTestHelper<T>() という名前の "TestHelper" メソッドに追加します。You do not add them to the method marked with the TestMethod attribute but to the "TestHelper" method, which for this test is named DataTestHelper<T>().

この例では、ジェネリック型パラメーター T には制約 where T : Employee が含まれています。In this example, the generic type parameter T has the constraint where T : Employee. この制約は、テスト メソッドでは満たされません。This constraint is not satisfied in the test method. そのため、DataTest() メソッドには、T に配置された型制約を指定する要件を通知する Assert ステートメントが含まれています。Therefore, the DataTest() method contains an Assert statement that alerts you to the requirement to supply the type constraint that has been placed on T. この Assert ステートメントのメッセージは、("No appropriate type parameter is found to satisfies the type constraint(s) of T. " + "Please call DataTestHelper<T>() with appropriate type parameters."); となります。The message of this Assert statement reads as follows: ("No appropriate type parameter is found to satisfies the type constraint(s) of T. " + "Please call DataTestHelper<T>() with appropriate type parameters.");

つまり、DataTest() テスト メソッドから DataTestHelper<T>() メソッドを呼び出す場合は、Employee 型のパラメーターまたは Employee から派生したクラスを渡す必要があります。In other words, when you call the DataTestHelper<T>() method from the test method, DataTest(), you must pass a parameter of type Employee or a class derived from Employee.

using ClassLibrary2;

using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace TestProject1

{  
    [TestClass()]  
    public class GenericList_NodeTest  
    {  

        public void DataTestHelper<T>()  
            where T : Employee  
        {  
            GenericList_Shadow<T>.Node target = new GenericList_Shadow<T>.Node(); // TODO: Initialize to an appropriate value  
            T expected = default(T); // TODO: Initialize to an appropriate value  
            T actual;  
            target.Data = expected;  
            actual = target.Data;  
            Assert.AreEqual(expected, actual);  
            Assert.Inconclusive("Verify the correctness of this test method.");  
        }  

        [TestMethod()]  
        public void DataTest()  
        {  
            Assert.Inconclusive("No appropriate type parameter is found to satisfies the type constraint(s) of T. " +  
            "Please call DataTestHelper<T>() with appropriate type parameters.");  
        }  
    }  
}  

関連項目See Also

単体テストの構造 Anatomy of a Unit Test
コードの単体テストUnit Test Your Code