Microsoft Fakes の shim を利用した単体テスト

Microsoft Fakes は単体テストのフレームワークで、「スタブ」と「shim」という機能があります。

shim は、コンパイル済みのアセンブリの挙動を単体テスト用に置き換える機能です。
例えば次に示すように、現在の時刻により挨拶文を切り替えるコードの単体テストをしたいときなどに有効です。


public static class Messages
{
    public static string HelloText
    {
        get
        {
            var hour = DateTime.Now.Hour;
            return
                4 <= hour && hour < 12 ? "おはようございます" :
                12 <= hour && hour < 17 ? "こんにちは" :
                "こんばんは";
        }
    }
}


 

System.DateTime 構造体は mscorlib.dll で定義されていますが、
mscorlib.dll または System.dll に対して Microsoft Fakes を利用するには、
ソリューション エクスプローラー上で、
テスト プロジェクトの [参照設定] から [System] を右クリックして [Fakes アセンブリに追加] をクリックします。

Fakes アセンブリに追加

 

この操作により、スタブや shim の挙動を格納するための Fakes アセンブリが作成されます (完了するまでに数秒かかります)。
ファイルの実体は、テスト プロジェクトの FakesAssemblies フォルダーに作成されます。

shim を利用した単体テストは、次のように記述します。


[TestClass]
public class MessagesTest
{
    [TestMethod]
    public void HelloText_1()
    {
        using (ShimsContext.Create())
        {
            System.Fakes.ShimDateTime.NowGet = () => new DateTime(2013, 7, 1, 9, 0, 0);
            Assert.AreEqual("おはようございます", Messages.HelloText);

            System.Fakes.ShimDateTime.NowGet = () => new DateTime(2013, 7, 1, 15, 0, 0);
            Assert.AreEqual("こんにちは", Messages.HelloText);

            System.Fakes.ShimDateTime.NowGet = () => new DateTime(2013, 7, 1, 21, 0, 0);
            Assert.AreEqual("こんばんは", Messages.HelloText);
        }
    }
}


System.DateTime 構造体に対して、System.Fakes.ShimDateTime という名前のクラスが作成されています。
Now プロパティの挙動を変更するには、NowGet というプロパティに関数を設定します。

 

次に、データベース接続に失敗した状況を擬似的に作り出す例を考えます。
以下のような、ADO.NET でデータベースからデータを取得するメソッドがあるとします。
(このコードは実用的ではありませんが。)


public static class Products
{
    const string NorthwindConnectionString = @"Data Source=.\SQLExpress;Initial Catalog=Northwind;Integrated Security=True";
    const string SelectCommandText = "select * from Products";

    public static bool FillProducts()
    {
        try
        {
            using (var da = new SqlDataAdapter(SelectCommandText, NorthwindConnectionString))
            using (var dt = new DataTable())
            {
                da.Fill(dt);
            }
            return true;
        }
        catch (SqlException)
        {
            return false;
        }
    }
}


 

この場合、まずテスト プロジェクトの System.Data.dll に対して Fakes アセンブリを作成します。

SqlConnection.Open メソッドの中で SqlException を発生させる挙動を実現すればよいことになりますが、
SqlException オブジェクトを自分で生成するのは難しいため
SqlConnection.Open メソッドの shim を断念し、その代わりに、
SqlConnection.ConnectionString プロパティの set で偽の接続文字列を設定させる方法で解決しました。


[TestClass]
public class ProductsTest
{
    const string FakeConnectionString = @"Data Source=.\SQLExpress;Initial Catalog=_Fake;Integrated Security=True";

    [TestMethod]
    public void FillProducts_1()
    {
        using (ShimsContext.Create())
        {
            System.Data.SqlClient.Fakes.ShimSqlConnection.AllInstances.ConnectionStringSetString = (c, s) =>
                ShimsContext.ExecuteWithoutShims(() => c.ConnectionString = FakeConnectionString);

            Assert.AreEqual(false, Products.FillProducts());
        }
    }
}


このようにすれば、データベース接続に失敗するテストケースを自動で実行できるようになります。

 

なお、Visual Studio の製品比較によると、
Visual Studio 2012 または 2013 で Microsoft Fakes を利用するには Ultimate または Premium エディションが必要です。

 

バージョン情報
Visual Studio 2012, 2013

参照
Microsoft Fakes を使用したテストでのコードの分離
Microsoft Fakes Frameworkの使い方

カテゴリー: ツール. タグ: , . Leave a Comment »