normalian blog

Let's talk about Microsoft Azure, ASP.NET and Java!

Moq.dllを使ってみた

ASP.NET MVC内のテストコードでも、華麗に使われているMoq.dllを少々使ってみた。こ奴が何者かという事に関しては「まずコードを見ろ!」と言いたいところですが、端的に述べると「単体テスト用のMockを作りやすくするライブラリ」でしょうか?前々からASP.NET MVC内部で眺めては居たのですが、実際使ってみてこいつの便利さを知ってみました。
で、肝心の取得場所ですが、Google Codeに公開されています。こちらからDL可能ですので、Moq.3.1.416.3現在のバイナリをDLしてください。

まず使ってみる

そもそも使い方がさっぱりわからんので、とりあえず使ってみる

[TestMethod()]
public void HttpSessionStateBase01()
{
    //NotImplementedExceptionが発生するかのテスト
    HttpSessionStateBase target = new Mock<HttpSessionStateBase>().Object;
    //でない!ひゃっほー
    target.Abandon();
}

とりあえず試してみた。モックを作りたいクラスをMockのジェネリックで指定してインスタンスを生成します(これがモックファクトリー的な物になってるのかな?)。作成したインスタンスに対して、Objectプロパティからモックインスタンスを生成します。
で、この例だとHttpSessionStateBase#Abandonメソッド呼んでますが、通常発生する筈のNotImplementedExceptionが発生しません。

簡単にプロパティを設定してみる

次は単にモックインスタンスを生成するだけでなく、プロパティも設定できるようにしてみます。

[TestMethod()]
public void HttpSessionStateBase02()
{
    //メソッドのセット
    bool expected = true;
    bool actual;

    Mock<HttpContextBase> mockHttpContext = new Mock<HttpContextBase>();
    Mock<HttpSessionStateBase> mockHttpSession = new Mock<HttpSessionStateBase>();
    mockHttpSession.Setup(session => session.IsNewSession).Returns(true);
    mockHttpContext.Setup(context => context.Session).Returns(mockHttpSession.Object);
    var httpContext = mockHttpContext.Object;

    //NewSessionをtrueにする!
    actual = httpContext.Session.IsNewSession;

    //ちゃんと帰ってきてる!
    Assert.AreEqual(expected, actual);
}

お次はHttpContextBaseクラス、HttpSessionStateBaseクラスそれぞれのモックを作成し、HttpSessionStateBase#IsNewSessionプロパティにtrueを設定しています。すげー、すげーよ!今まで必死に独自モッククラスを作っていたのが嘘みたいだよ!

インデクサも設定

次にインデクサ系も設定してみた。だいたい以下な感じでモックを生成できます。

[TestMethod()]
public void HttpSessionStateBase03()
{
    //メソッドのセット
    string expected = "Hello Moq Study";
    string actual;

    Mock<HttpContextBase> mockHttpContext = new Mock<HttpContextBase>();
    Mock<HttpSessionStateBase> mockHttpSession = new Mock<HttpSessionStateBase>();
    mockHttpSession.Setup(session => session["viewData"]).Returns("Hello Moq Study");
    mockHttpContext.Setup(context => context.Session).Returns(mockHttpSession.Object);
    var httpContext = mockHttpContext.Object;
    actual = httpContext.Session["viewData"] as string;

    //ちゃんとハッシュ系にも値が仕込まれてる
    Assert.AreEqual(expected, actual);
}

うーん、テラ便利。いざASP.NET系のテストをするとき、インスタンス生成に困るHttpContextBaseやら、HttpSessionStateBaseやらのインスタンスをこうも簡単に作れるとは…。

ユーザ認証

最後にユーザ認証を試してみる。

        [TestMethod()]
        public void IIdentity01()
        {
            Mock<HttpSessionStateBase> mockHttpSession = new Mock<HttpSessionStateBase>();
            Mock<IPrincipal> mockIPrincipal = new Mock<IPrincipal>();
            Mock<IIdentity> mockIdentity = new Mock<IIdentity>();
            mockIdentity.Setup(identity => identity.IsAuthenticated).Returns(true);
            mockIdentity.Setup(identity => identity.Name).Returns("normalian");
            mockIPrincipal.Setup(principal => principal.Identity).Returns(mockIdentity.Object);
            //mockIPrincipal.Setup(principal => principal.IsInRole ).Returns( name => "normalian" == name );
            //ここは無理

            var User = mockIPrincipal.Object;

            //認証されて、ユーザ名も設定済み
            Assert.AreEqual(true, User.Identity.IsAuthenticated);
            Assert.AreEqual("normalian", User.Identity.Name);
        }

User認証の設定、ユーザオブジェクトのユーザ名もきっちり設定されてる!これでもうASP.NETだろうが、Silverlightだろうが怖くないっす!!