4

ええと...問題はもっと複雑です、そして質問のタイトルは言います。まず、HtmlHelperの拡張メソッドがあります。これは、現在のルートパラメーターに基づいてパラメーターを使用してhtmlリンクを生成します。つまり、ページにいる場合、たとえばリンクを生成するため.../page?param1=val1&param2=val2にメソッドを呼び出すと、へのリンクが取得されます。さて、拡張クラス自体は次のとおりです。ActionQuryLink@Html.ActionQuryLink("link text", "action", new { param3 = "value3" })<a href=".../page?param1=val1&param2=val2&param3=value3">link text</a>

public static class ActionLinkHelper
    {
        public static MvcHtmlString ActionQueryLink(this HtmlHelper htmlHelper, string linkText, string action)
        {
            return (ActionQueryLink(htmlHelper, linkText, action, null, null));
        }
        public static MvcHtmlString ActionQueryLink(this HtmlHelper htmlHelper, string linkText, string action, object routeValues)
        {

            /*line 16*/return (ActionQueryLink(htmlHelper, linkText, action, routeValues, null));
        }

        public static MvcHtmlString ActionQueryLink(this HtmlHelper htmlHelper, string linkText, string action, object routeValues, IDictionary<string, object> htmlAttributes)
        {
            var queryString = htmlHelper.ViewContext.HttpContext.Request.QueryString;

            var newRoute = routeValues == null
                ? htmlHelper.ViewContext.RouteData.Values
                : new RouteValueDictionary(routeValues);

            foreach(string key in queryString.Keys)
            {
                if(!newRoute.ContainsKey(key))
                    newRoute.Add(key, queryString[key]);
            }
            /*line 32*/string generatedLink = HtmlHelper.GenerateLink(
                htmlHelper.ViewContext.RequestContext,
                htmlHelper.RouteCollection,
                linkText,
                null,
                action,
                null,
                newRoute,
                htmlAttributes);

            return new MvcHtmlString(generatedLink);
        }
    }

主な問題は、この拡張メソッドをテストすることです

私の単体テストは次のようになります。

[TestClass]
    public class ActionLinkHeplerTests
    {
        #region ActionQueryLink
        [TestMethod]
        public void ActionLinkHeplerShouldGenerateCorrectActionLink()
        {
            var mockHttpContext = new Mock<HttpContextBase>();
            mockHttpContext.Setup(c => c.Request.QueryString).Returns(new NameValueCollection { { "param1", "value1" } });
            mockHttpContext.Setup(c => c.Request.AppRelativeCurrentExecutionFilePath).Returns("~/");
            mockHttpContext.Setup(c => c.Request.ApplicationPath).Returns("~/");
            mockHttpContext.Setup(c => c.Request.CurrentExecutionFilePath).Returns("~/");

            var mockProductRepository = new Mock<IProductRepository>();
            mockProductRepository.Setup(p => p.GetCategory(It.IsAny<string>())).Returns(new Category());
            var mockSettings = new Mock<ISettings>();
            var categoryController = new CategoryController(mockProductRepository.Object, mockSettings.Object);

            var mockViewDataContainer = new Mock<IViewDataContainer>();
            mockViewDataContainer.Setup(e => e.ViewData).Returns(new ViewDataDictionary { { "action", "action" } });

            var viewContext = new ViewContext
                                  {
                                      HttpContext = categoryController.HttpContext,
                                      RequestContext = new RequestContext
                                                           {
                                                               HttpContext = mockHttpContext.Object,
                                                               RouteData = new RouteData()
                                                           }
                                  };

            var mockRouteHandler = new Mock<IRouteHandler>();
            var helper = new HtmlHelper(viewContext, mockViewDataContainer.Object, new RouteCollection { { "action", new Route("controller/action", mockRouteHandler.Object) } });

            var expected = new MvcHtmlString("");
            /*line 51*/var actual = helper.ActionQueryLink("link text", "action", new {view = "list"});

            Assert.AreEqual(expected, actual);
        }
        #endregion
    }

そして、私はそのような例外を受け取ります:

Test method TestSite.UnitTests.Helpers.ActionLinkHeplerTests.ActionLinkHeplerShouldGenerateCorrectActionLink threw exception: 
System.NullReferenceException: Object reference not set to an instance of an object.

およびスタックトレース:

at System.Web.UI.Util.GetUrlWithApplicationPath(HttpContextBase context, String url)
   at System.Web.Routing.RouteCollection.NormalizeVirtualPath(RequestContext requestContext, String virtualPath)
   at System.Web.Routing.RouteCollection.GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
   at System.Web.Mvc.RouteCollectionExtensions.GetVirtualPathForArea(RouteCollection routes, RequestContext requestContext, String name, RouteValueDictionary values, ref Boolean usingAreas)
   at System.Web.Mvc.UrlHelper.GenerateUrl(String routeName, String actionName, String controllerName, RouteValueDictionary routeValues, RouteCollection routeCollection, RequestContext requestContext, Boolean includeImplicitMvcValues)
   at System.Web.Mvc.UrlHelper.GenerateUrl(String routeName, String actionName, String controllerName, String protocol, String hostName, String fragment, RouteValueDictionary routeValues, RouteCollection routeCollection, RequestContext requestContext, Boolean includeImplicitMvcValues)
   at System.Web.Mvc.HtmlHelper.GenerateLinkInternal(RequestContext requestContext, RouteCollection routeCollection, String linkText, String routeName, String actionName, String controllerName, String protocol, String hostName, String fragment, RouteValueDictionary routeValues, IDictionary`2 htmlAttributes, Boolean includeImplicitMvcValues)
   at System.Web.Mvc.HtmlHelper.GenerateLink(RequestContext requestContext, RouteCollection routeCollection, String linkText, String routeName, String actionName, String controllerName, String protocol, String hostName, String fragment, RouteValueDictionary routeValues, IDictionary`2 htmlAttributes)
   at System.Web.Mvc.HtmlHelper.GenerateLink(RequestContext requestContext, RouteCollection routeCollection, String linkText, String routeName, String actionName, String controllerName, RouteValueDictionary routeValues, IDictionary`2 htmlAttributes)
   at Core.Helpers.ActionLinkHelper.ActionQueryLink(HtmlHelper htmlHelper, String linkText, String action, Object routeValues, IDictionary`2 htmlAttributes) in ActionLinkHelper.cs: line 32
   at Core.Helpers.ActionLinkHelper.ActionQueryLink(HtmlHelper htmlHelper, String linkText, String action, Object routeValues) in ActionLinkHelper.cs: line 16
   at TestSite.UnitTests.Helpers.ActionLinkHeplerTests.ActionLinkHeplerShouldGenerateCorrectActionLink() in ActionLinkHeplerTests.cs: line 51

まあ、私はそのようなコードのバッチを本当に申し訳ありません。 しかし、私はこの問題に約3日間取り組んでいます。ご覧のとおり、一部のMVCライブラリではなく、でエラーが発生しSystem.Web.UI.Utilます。ソースを見つけSystem.Web.UI.Utilてそれをもう1つのプロジェクトとしてソリューションに追加できたとしても、MVCフレームワークにこのプロジェクトの代わりにこのプロジェクトを使用させることはできませんでした。System.Web.UI.Utilグローバルアセンブリキャッシュから。正直なところ、ソリューションでMVCをGACからMVCのソースプロジェクトに置き換えることは非常に困難です。これは、非常に複雑で、多くの依存関係があり、それを実行しようとすると、多くのエラーが発生し、それらのほとんどがグローバルアセンブリキャッシュからのMVCアセンブリをすでに使用している外部ライブラリのものでした。また、最も重要なことは、私のヘルパーメソッドが私のプロジェクトで正常に機能し、テスト中にのみ例外を呼び出すことです。したがって、私の提案は、ヘルパーのテスト条件が完全ではないか、おそらく間違っているということです。要約すると、私の質問は、Moqを使用してHTMLヘルパー拡張メソッドの正しい条件をどのようにモックできるかということです。

4

1 に答える 1

10

ルーティング情報に依存するヘルパーをテストするには、次のメソッドをモックする必要があることが判明しましたRequestContext.HttpContext

  • RequestContext.HttpContext.Request.ApplicationPath-ルートパスに似たものを返す必要があります(つまり@"/"
  • RequestContext.HttpContext.Response.ApplyAppPathModifier- 入力引数を単純に返すことができます:

サンプル:

request.Setup(r => r.ApplicationPath).Returns(@"/");
response.Setup(r => r.ApplyAppPathModifier(It.IsAny<string>()))
                .Returns((string s) => s);
于 2013-03-19T03:03:21.567 に答える