【问题标题】:MVC 4 Mocking HttpContext - how to mock DisplayModeProviderMVC 4 Mocking HttpContext - 如何模拟 DisplayModeProvider
【发布时间】:2012-11-12 17:10:38
【问题描述】:

我目前正在使用Scott Hanselmans HTTP context mock 进行单元测试。这在 MVC 3 上运行良好,而且从不回头,我用它来测试以下代码的调用。

public class PartialViewRenderer : IPartialViewRenderer
{
    public string Render(Controller controller, string viewName, object model)
    {
        if (string.IsNullOrEmpty(viewName))
            viewName = controller.ControllerContext.RouteData.GetRequiredString("action");

        controller.ViewData.Model = model;

        using (StringWriter sw = new StringWriter())
        {
            ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
            ViewContext viewContext = new ViewContext(controller.ControllerContext, viewResult.View,
                                                      controller.ViewData, controller.TempData, sw);
            viewResult.View.Render(viewContext, sw);

            return sw.GetStringBuilder().ToString();
        }
    }
}

当我第一次将我的应用程序转换为 MVC 4 时,我遇到了问题,它出现了运行时异常。因此,我尝试通过并修复需要修复的内容,这使我改变了 Hanselmans MockHelpers 上的以下方法:(我基本上更改了 HttpContext.Items 以返回,因为它吹出了“null”异常)

 public static HttpContextBase FakeHttpContext()
    {
        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 cookies = new HttpCookieCollection();
        var items = new ListDictionary();

        request.Setup(r => r.Cookies).Returns(cookies);
        response.Setup(r => r.Cookies).Returns(cookies);

        context.Setup(ctx => ctx.Items).Returns(items);

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

        return context.Object;
    }

 public static void SetFakeControllerContext(this Controller controller, RouteData route)
    {
        var httpContext = FakeHttpContext();

        ControllerContext context = new ControllerContext(new RequestContext(httpContext, route), controller);

        controller.ControllerContext = context;
    }

这是一个非常简单的 nUnit 测试,我必须尝试确定我需要对这个 http 上下文模拟进行哪些更改(我什至还没有放入断言)

    [Test]
    public void test()
    {
        _contactsController = _container.Resolve<ContactsController>();

        var route = new RouteData();

        route.Values.Add("controller", "ContactsController");
        route.Values.Add("action", "GetEditContactDetailsDialog");

        _contactsController.SetFakeControllerContext(route);

        var result = _contactsController.GetEditContactDetailsDialog("1");
    }

现在,当我运行此测试时,它会在 ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName); 行上的 PartialViewRenderer.Render 调用上炸毁这是以下堆栈跟踪。

在 System.Web.WebPages.DisplayModeProvider.<.ctor>b__2(HttpContextBase 上下文) 在 System.Web.WebPages.DefaultDisplayMode.CanHandleContext(HttpContextBase httpContext) 在 System.Web.WebPages.DisplayModeProvider.c__DisplayClass6.b__5(IDisplayMode 模式) 在 System.Linq.Enumerable.WhereListIterator1.MoveNext() at System.Collections.Generic.List1..ctor(IEnumerable1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable1 源) 在 System.Web.WebPages.DisplayModeProvider.GetAvailableDisplayModesForContext(HttpContextBase httpContext,IDisplayMode currentDisplayMode) 在 System.Web.Mvc.VirtualPathProviderViewEngine.GetPath(ControllerContext controllerContext, String[] locations, String[] areaLocations, String locationsPropertyName, String name, String controllerName, String cacheKeyPrefix, Boolean useCache, String[]& searchedLocations)

看来我无法进入并模拟 DisplayModeProvider。 Per the MVC source Code 有没有人可以解决这个问题?我无法在任何地方找到解决方案。

【问题讨论】:

  • 我遇到了关于模拟 DisplayMode 的类似问题。我想知道你是否能找到任何解决方案?

标签: .net asp.net-mvc-4 nunit moq


【解决方案1】:

首先,使用MockBehavior.Strict 进行初始化模拟,例如:

var context = new Mock<HttpContextBase>(MockBehavior.Strict);

使用它,您可以找到与 DisplayMode 的依赖关系。

第二,DisplayMode是asp.net mvc 4的新特性:

http://www.asp.net/whitepapers/mvc4-release-notes#_Toc303253810

所以,它得到Request.Browser 参数来确定使用哪个视图。为浏览器添加 Mock:

var browser = new Mock<HttpBrowserCapabilitiesBase>(MockBehavior.Strict);
var context = new Mock<HttpContextBase>(MockBehavior.Strict);
var request = new Mock<HttpRequestBase>(MockBehavior.Strict);
var response = new Mock<HttpResponseBase>(MockBehavior.Strict);
var session = new Mock<HttpSessionStateBase>(MockBehavior.Strict);
var server = new Mock<HttpServerUtilityBase>(MockBehavior.Strict);
var cookies = new HttpCookieCollection();
var items = new ListDictionary();

browser.Setup(b => b.IsMobileDevice).Returns(false);

request.Setup(r => r.Cookies).Returns(cookies);
request.Setup(r => r.ValidateInput());
request.Setup(r => r.UserAgent).Returns("Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11");
response.Setup(r => r.Cookies).Returns(cookies);

request.Setup(r => r.Browser).Returns(browser.Object);
context.Setup(ctx => ctx.Items).Returns(items);

【讨论】:

  • 我还没有让它工作。我现在遇到另一个错误,我希望今晚能解决这个问题。
  • 在调用 ViewEngineCollection.FindPartialView() 时似乎缺少一些东西,因为它在 System.Web.Web.Pages.FileExcistenceCache 构造函数中以 NullReferenceException 失败。这个答案可能适用于其他场景,比如魅力,只是在我观察的情况下(还没有)。
【解决方案2】:

DisplayMode 实现了接口IDisplayMode,因此您应该能够(使用 Moq)创建一个模拟来注入。 DisplayModeProvider 有一个 SetDisplayMode(受保护)方法,您可以通过反射调用。

【讨论】:

    猜你喜欢
    • 2010-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-01
    • 1970-01-01
    • 2013-10-01
    相关资源
    最近更新 更多