如何进行单元测试以在 ASP.NET MVC 中使用路由?

发布于 2024-08-14 14:06:16 字数 1710 浏览 2 评论 0原文

我正在针对 ASP.NET MVC 应用程序编写单元测试,特别是正在测试我编写的 HtmlHelper 扩展方法。扩展方法内部有一行:

var innerHtml = htmlHelper.ActionLink(text, action, controller, routeValues, null);

当我在单元测试内部运行此行时,无论传入的操作或控制器如何,生成的 URL 的 href 都是空白。

这是我的单元测试:

var page = CreateProductDataPage(); //returns ProductDataPage object
var htmlHelper = Http.CreateHtmlHelperWithMocks<ProductDataPage>(new ViewDataDictionary<ProductDataPage>(page), false);
var result = htmlHelper.ProductListingBreadcrumb(true, null, null);

这是 CreateHtmlHelperWithMocks 方法:

public static HtmlHelper<T> CreateHtmlHelperWithMocks<T>(ViewDataDictionary<T> viewData, bool isLoggedIn) where T : class
{
    var mockViewDataContainer = new Mock<IViewDataContainer>();
    mockViewDataContainer.SetupGet(v => v.ViewData).Returns(viewData);

    return new HtmlHelper<T>(GetViewContextMock(viewData, isLoggedIn).Object, mockViewDataContainer.Object);
}

最后,这是 GetViewContextMock 方法:

public static Mock<ViewContext> GetViewContextMock(ViewDataDictionary viewData, bool isLoggedIn)
{
    var mock = new Mock<ViewContext>();

    mock.SetupGet(v => v.HttpContext).Returns(GetHttpContextMock(isLoggedIn).Object);
    mock.SetupGet(v => v.Controller).Returns(new Mock<ControllerBase>().Object);
    mock.SetupGet(v => v.View).Returns(new Mock<IView>().Object);
    mock.SetupGet(v => v.ViewData).Returns(viewData);
    mock.SetupGet(v => v.TempData).Returns(new TempDataDictionary());
    mock.SetupGet(v => v.RouteData).Returns(new RouteData());

    return mock;
}

I am writing unit tests against my ASP.NET MVC application, in particular I am testing an HtmlHelper extension method that I wrote. There is a line inside of the extension method:

var innerHtml = htmlHelper.ActionLink(text, action, controller, routeValues, null);

When I run this inside of my unit test, the href of the generated URL is blank regardless of the action or controller passed in.

Here is my unit test:

var page = CreateProductDataPage(); //returns ProductDataPage object
var htmlHelper = Http.CreateHtmlHelperWithMocks<ProductDataPage>(new ViewDataDictionary<ProductDataPage>(page), false);
var result = htmlHelper.ProductListingBreadcrumb(true, null, null);

Here is the CreateHtmlHelperWithMocks method:

public static HtmlHelper<T> CreateHtmlHelperWithMocks<T>(ViewDataDictionary<T> viewData, bool isLoggedIn) where T : class
{
    var mockViewDataContainer = new Mock<IViewDataContainer>();
    mockViewDataContainer.SetupGet(v => v.ViewData).Returns(viewData);

    return new HtmlHelper<T>(GetViewContextMock(viewData, isLoggedIn).Object, mockViewDataContainer.Object);
}

Finally, here is the GetViewContextMock method:

public static Mock<ViewContext> GetViewContextMock(ViewDataDictionary viewData, bool isLoggedIn)
{
    var mock = new Mock<ViewContext>();

    mock.SetupGet(v => v.HttpContext).Returns(GetHttpContextMock(isLoggedIn).Object);
    mock.SetupGet(v => v.Controller).Returns(new Mock<ControllerBase>().Object);
    mock.SetupGet(v => v.View).Returns(new Mock<IView>().Object);
    mock.SetupGet(v => v.ViewData).Returns(viewData);
    mock.SetupGet(v => v.TempData).Returns(new TempDataDictionary());
    mock.SetupGet(v => v.RouteData).Returns(new RouteData());

    return mock;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

一场春暖 2024-08-21 14:06:16

更新:弄清楚了。 a$$ 真是太痛苦了。万一其他人尝试这样做...

第一步是在创建模拟 HtmlHelper 时添加来自 global.asax 的路线集合。

    public static HtmlHelper<T> CreateHtmlHelperWithMocks<T>(ViewDataDictionary<T> viewData, bool isLoggedIn) where T : class
    {
        var mockViewDataContainer = new Mock<IViewDataContainer>();
        mockViewDataContainer.SetupGet(v => v.ViewData).Returns(viewData);

        //These next two lines are key:
        var routeCollection = new RouteCollection();
        MvcApplication.RegisterRoutes(routeCollection);

        return new HtmlHelper<T>(GetViewContextMock(viewData, isLoggedIn).Object, mockViewDataContainer.Object, routeCollection);
    }

然后,我必须确保 HttpContext 模拟为请求的 ApplicationPath 属性和响应的 ApplyAppPathModifier 方法返回结果。

    public static Mock<HttpContextBase> GetHttpContextMock(bool isLoggedIn)
    {
        var context = new Mock<HttpContextBase>();
        var request = new Mock<HttpRequestBase>();
        var response = new Mock<HttpResponseBase>();
        var session = new Mock<HttpSessionStateBase>();
        var server = new Mock<HttpServerUtilityBase>();
        var principal = AuthenticationAndAuthorization.GetPrincipleMock(isLoggedIn);

        //These next two lines are required for the routing to generate valid URLs, apparently:
        request.SetupGet(r => r.ApplicationPath).Returns("/");
        response.Setup(r => r.ApplyAppPathModifier(It.IsAny<string>())).Returns((string r) => r);

        context.SetupGet(c => c.Request).Returns(request.Object);
        context.SetupGet(c => c.Response).Returns(response.Object);
        context.SetupGet(c => c.Session).Returns(session.Object);
        context.SetupGet(c => c.Server).Returns(server.Object);
        context.SetupGet(c => c.User).Returns(principal.Object);

        return context;
    }

Update: Figured it out. What a pain in the a$$. In case anyone else tries to do this...

The first step was to add the Route Collection from the global.asax in the creation of the mock HtmlHelper.

    public static HtmlHelper<T> CreateHtmlHelperWithMocks<T>(ViewDataDictionary<T> viewData, bool isLoggedIn) where T : class
    {
        var mockViewDataContainer = new Mock<IViewDataContainer>();
        mockViewDataContainer.SetupGet(v => v.ViewData).Returns(viewData);

        //These next two lines are key:
        var routeCollection = new RouteCollection();
        MvcApplication.RegisterRoutes(routeCollection);

        return new HtmlHelper<T>(GetViewContextMock(viewData, isLoggedIn).Object, mockViewDataContainer.Object, routeCollection);
    }

Then I had to make sure the HttpContext mock had a result being returned for the Request's ApplicationPath property and the Response's ApplyAppPathModifier method.

    public static Mock<HttpContextBase> GetHttpContextMock(bool isLoggedIn)
    {
        var context = new Mock<HttpContextBase>();
        var request = new Mock<HttpRequestBase>();
        var response = new Mock<HttpResponseBase>();
        var session = new Mock<HttpSessionStateBase>();
        var server = new Mock<HttpServerUtilityBase>();
        var principal = AuthenticationAndAuthorization.GetPrincipleMock(isLoggedIn);

        //These next two lines are required for the routing to generate valid URLs, apparently:
        request.SetupGet(r => r.ApplicationPath).Returns("/");
        response.Setup(r => r.ApplyAppPathModifier(It.IsAny<string>())).Returns((string r) => r);

        context.SetupGet(c => c.Request).Returns(request.Object);
        context.SetupGet(c => c.Response).Returns(response.Object);
        context.SetupGet(c => c.Session).Returns(session.Object);
        context.SetupGet(c => c.Server).Returns(server.Object);
        context.SetupGet(c => c.User).Returns(principal.Object);

        return context;
    }
装迷糊 2024-08-21 14:06:16

大约一个月前,我在博客中介绍了如何使用 Rhino.Mocks 进行此操作。您可以在 http://farm-fresh-code.blogspot.com/2009/10/mocking-htmlhelper-class-with.html。基本上,我的解决方案是在模拟中提供所有内容,包括在 RouteData 中以及通过连接到模拟助手的 Response 对象上的 ApplyAppPathModifier。它实际上更像是一个基于底层存根的假助手。

I blogged about doing this with Rhino.Mocks about a month ago. You can find more information on how I handle this at http://farm-fresh-code.blogspot.com/2009/10/mocking-htmlhelper-class-with.html. Basically, my solution is to provide everything in the mock, both in the RouteData and via the ApplyAppPathModifier on the Response object connected to the mock helper. It's actually more of a fake helper based on underlying stubs.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文