3

私の MVC4 Web アプリケーションには、Response オブジェクトを使用してクエリ文字列変数などにアクセスする特定のコントローラー アクションがあります。アクションの単体テストを妨げないように抽象化するためのベストプラクティスは何ですか?

4

1 に答える 1

5

MVC4 チームは、HttpContext関連するプロパティを抽象化してモックできるようにしました。Response現在は型HttpResponseBaseになっているため、すでに抽象化されています。それへの呼び出しをモックすることができます。

以下は、単体テスト シナリオでコントローラーを初期化するために過去に使用した標準的な方法です。それはMOQに関してです。必要に応じて、さまざまな関連プロパティをモック化する偽の http コンテキストを作成します。正確なシナリオに合わせてこれを変更できます。

コントローラーをインスタンス化した後、それをこのメソッドに渡します (おそらく基本クラスで - 単体テストに NBehave を使用しますが、特にここに関連するもので水を濁すことはしません):

protected void InitialiseController(T controller, NameValueCollection collection, params string[] routePaths)
{
    Controller = controller;
    var routes = new RouteCollection();
    RouteConfig.RegisterRoutes(routes);
    var httpContext = ContextHelper.FakeHttpContext(RelativePath, AbsolutePath, routePaths);
    var context = new ControllerContext(new RequestContext(httpContext, new RouteData()), Controller);
    var urlHelper = new UrlHelper(new RequestContext(httpContext, new RouteData()), routes);
    Controller.ControllerContext = context;
    Controller.ValueProvider = new NameValueCollectionValueProvider(collection, CultureInfo.CurrentCulture);
    Controller.Url = urlHelper;
}

ContextHelperモックがすべて設定されている場所です。

public static class ContextHelper
{
    public static HttpContextBase FakeHttpContext(string relativePath, string absolutePath, params string[] routePaths)
    {
        var httpContext = new Mock<HttpContextBase>();
        var request = new Mock<HttpRequestBase>();
        var response = new Mock<HttpResponseBase>();
        var session = new Mock<HttpSessionStateBase>();
        var server = new Mock<HttpServerUtilityBase>();
        var cookies = new HttpCookieCollection();

        httpContext.Setup(x => x.Server).Returns(server.Object);
        httpContext.Setup(x => x.Session).Returns(session.Object);
        httpContext.Setup(x => x.Request).Returns(request.Object);
        httpContext.Setup(x => x.Response).Returns(response.Object);
        response.Setup(x => x.Cookies).Returns(cookies);
        httpContext.SetupGet(x => x.Request.Url).Returns(new Uri("http://localhost:300"));
        httpContext.SetupGet(x => x.Request.UserHostAddress).Returns("127.0.0.1");
        if (!String.IsNullOrEmpty(relativePath))
        {
            server.Setup(x => x.MapPath(relativePath)).Returns(absolutePath);
        }

        // used for matching routes within calls to Url.Action
        foreach (var path in routePaths)
        {
            var localPath = path;
            response.Setup(x => x.ApplyAppPathModifier(localPath)).Returns(localPath);
        }

        var writer = new StringWriter();
        var wr = new SimpleWorkerRequest("", "", "", "", writer);
        HttpContext.Current = new HttpContext(wr);
        return httpContext.Object;
    }
}

私は最近、このアプローチをカバーするブログ投稿を書きましたが、Nsubstitute代わりにモック フレームワークとして使用しMOQます。

NUnit と NSubstitute を使用したコントローラーの単体テスト

于 2013-04-01T22:02:32.287 に答える