SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

Visual Studio 11 betaの単体テスト機能を使ってみよう!

単体テストエクスプローラーと、Fakes Frameworkの使い方を紹介

  • X ポスト
  • このエントリーをはてなブックマークに追加

Fakesのスタブとシムを使ったテスト方法

 Fakesは、Microsoft Researchで研究されていた「Pex and Moles」の中から、MolesだけがVS11betaに組み込まれたものです。

 Fakesを使うと、インターフェースや抽象クラスに実装を与えたり(スタブ)、既存のバイナリーに任意の実装を差し込んだり(シム)することができます。Fakesを使うには、Microsoft.QualityTools.Testing.Fakesへの参照設定とusingの指定が必要です。また、テスト対象を変更したときはリビルドが必要です。なお、MSTestだけでなく他のテスティングフレームワークからも利用可能です。

 詳しくはMSDNの「Isolating Unit Test Methods with Microsoft Fakes」(執筆時点では機械翻訳)をご覧ください。

スタブの使い方1:インターフェースに実装を与える

 テストしたい製品コードに次のインターフェースがあるとします。

【製品コード】IGreeting.cs:製品コード側のインターフェース
public interface IGreeting
{
    int Hour { get; }
    string GetGreeting();
}

 このインターフェースのGetGreeting()メソッドに、Fakesのスタブ機能を使って実装を与えるには、次のようにします。

【テストコード】GreetingTest.cs:インターフェースのスタブ(NUnitでテスト)
// interface のスタブ
[TestCase()]
public void Stub使用例_GetGreetingTest01()
{
    var greetStub = new StubIGreeting() { GetGreeting = () => "おはよう", };
    // インターフェースの実装をラムダ式で与える

    Assert.AreEqual("おはよう", greetStub.GetGreeting());
}

 もしもインテリセンスにStubIGreetingが出てこなければ、Microsoft.QualityTools.Testing.Fakesへの参照設定を確かめた上で、リビルドしてみてください。

スタブの使い方2:仮想メソッドや仮想プロパティに別の実装を与える

 テストしたい製品コードに次のような仮想プロパティを持ったクラスがあるとします。

【製品コード】Greeting.cs:仮想プロパティを持つクラス
public class Greeting : IGreeting
{
    public virtual int Hour
    {
        get { return DateTimeOffset.Now.Hour; }
    }

    public string GetGreeting()
    {
        //(略)
    }
}

 このHourプロパティに、Fakesのスタブ機能を使って別の実装を与えることができます。

【テストコード】GreetingTest.cs:仮想プロパティの実装を置き換える(NUnitでテスト)
// virtual メソッドやプロパティを持つクラスのスタブ
[TestCase(5, "おはよう")]
public void Stub使用例_GetGreetingTest02(int hour, string expected)
{
    var greetStub = new StubGreeting() { HourGet = () => hour, };
    // virtual メソッドやプロパティは、置き換えることができる

    Assert.AreEqual(expected, greetStub.GetGreeting());
}

 ここでは、本来の実装がシステムクロックに依存しているところを、引数で与えた時刻が返されるように実装を置き換えています。

 なお、実装として与えるラムダ式の中にAssert文を埋め込めば、Mockのように正しい引数が渡されたかどうかをテストすることも可能です。

シムの使い方:バイナリー中のメソッドなどへのアクセスに、実装を差し挟む

 シム(shim)とは、割れ目をふさいだり家具を水平にするために差し込む、薄い木片や金属片のことです。既存の実装との間に挟み込んで、その実装へのアクセスを横取りしてしまいます。非常に強力な機能ですが、その分、テストの実行に時間が掛かりますので、濫用しないように気を付けてください。

 上記のGreetingクラスのHourプロパティを、テストファーストで書こうと思ったとします。しかし、DateTimeOffset.Nowの値は刻一刻と変わってしまいますから、うまくテストが書けませんね。Fakesのシムの機能を使えば、次のようにできます。

 まず、DateTime構造体が入っているSystemアセンブリを指定してFakesアセンブリを作ります。

Fakesアセンブリに追加する
Fakesアセンブリに追加

 プロジェクトの参照設定でSystemを右クリックして[Fakesアセンブリに追加]を選ぶ(上図)と、System.4.0.0.0.FakesなどいくつかのFakesアセンブリが自動生成されます。そうしたら、次のようにShimsContextを使ってテストコードを記述できます。

【テストコード】GreetingTest.cs:DateTime.Nowを置き換える(NUnitでテスト)
// System.DateTime.Now に対するアクセスに、シム(shim)を挟み込む
[TestCase()]
public void Shim使用例_HourTest()
{
    // Hour プロパティを実装するために、
    // DateTimeOffset.Now が特定の値を返してくるようにする

    using (ShimsContext.Create())
    {
        ShimDateTime.NowGet 
            = () => new DateTime(2012, 3, 20, 21, 32, 43);
        // using を抜けるまで、DateTime.Now の読み取りは 21:32:43 を返し続ける
                
        Assert.AreEqual(21, (new Greeting()).Hour);
    }
}

 上の画像の左側に、このテストを含む実行結果が出ています。他のテストはだいたいミリ秒のオーダーで終了しているのに、シムを使ったテストは100ミリ秒のオーダーになっていることに注意してください。シムの機能は強力なので、開発中の製品コードに対しても利用したくなるかもしれませんが、ソースコードがあるときはテスト実行時間の短いスタブ機能を使うようにしましょう。

まとめ

  • VS11betaでは、NUnitなどのサードパーティ製テスティングツールも、MSTestと同様に利用できるようになった。
  • MSTestは、Expressを含む全エディションに搭載され、asyncメソッドのテストが書きやすくなっている。また、ネイティブコードのテストもできるようになった。
  • Fakesは、テスト時に実装を置き換える強力な機能を持っている。
修正履歴

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
特集記事連載記事一覧

もっと読む

この記事の著者

biac(ばいあっく)

HONDA R&Dで自動車の設計をやっていた機械屋さんが、技術の進化スピードに魅かれてプログラマーに。以来30年ほど、より良いコードをどうやったら作れるか、模索の人生。わんくま同盟の勉強会(名古屋)で、よく喋ってたりする。2014/10~2019/6 Microsoft MVP (Windows Devel...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/6491 2012/04/12 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング