C# 在控制器**外部的MVC**中模拟HttpContext

C# 在控制器**外部的MVC**中模拟HttpContext,c#,asp.net-mvc-3,moq,viewmodel,httpcontext,C#,Asp.net Mvc 3,Moq,Viewmodel,Httpcontext,场景 我们正在开发一个新的MVCWeb项目,并试图遵循本文中描述的Skinny Controller模式 作为我们行动的一部分,我们正在从缓存中检索一些导航数据(菜单结构) 问题 为了维护skinny controller模式,我们希望在ViewModel中使用缓存检查调用,我们已经尝试过,并且知道它可以使用以下代码 var cachedCategories = (List<Category>)HttpContext.Current.Cache["Categories"]; if (

场景

我们正在开发一个新的MVCWeb项目,并试图遵循本文中描述的Skinny Controller模式

作为我们行动的一部分,我们正在从缓存中检索一些导航数据(菜单结构)

问题

为了维护skinny controller模式,我们希望在ViewModel中使用缓存检查调用,我们已经尝试过,并且知道它可以使用以下代码

var cachedCategories = (List<Category>)HttpContext.Current.Cache["Categories"];
if (cachedCategories == null) {
       cachedCategories = _service.GetCategories().ToList<Category>();
       HttpContext.Current.Cache["Categories"] = cachedCategories;
}
var cachedCategories=(List)HttpContext.Current.Cache[“Categories”];
if(cachedCategories==null){
cachedCategories=_service.GetCategories().ToList();
HttpContext.Current.Cache[“Categories”]=cachedCategories;
}
然而,当涉及到单元测试时,我们遇到了一个问题。因为我们没有直接将HttpContext传递到ViewModel中,所以我们不知道如何模拟HttpContext

我们正在使用Moq,虽然我们有一些选项(一个是在实例化时将上下文从控制器传递到viewmodel),但这些选项需要更改代码以使测试正常工作


有人有什么建议吗?

模仿HttpContext是一项巨大的工作,因为它是你一生中看到的最大对象之一,所以最好不要模仿它(http://volaresystems.com/Blog/post/Dont-mock-HttpContext.aspx)
无论如何,您可以使用MVCcontrib中的一个(http://www.codeplex.com/mvcContrib)MvcMockHelps文件显示了它是如何完成的。

最终我们选择修改代码,以便于测试


我们通过在实例化时将HttpContext传递给ViewModel实现了这一点,正如我在最初的问题中提到的。

可以在控制器上放置一个可分配给局部变量的属性,如果该属性为null,它将分配HttpContect.Current,并返回HttpContextBase,您可以从测试中分配HttpContextBase。事实上,如果您使用的是IoC框架,您可以自动将HttpContext.Current分配给HttpContextBase属性(或构造函数),那么您可以只拥有一个字段或自动属性。(嗯,我想接下来的博客文章;))添加一个只用于测试目的的属性是我们提出的选项之一,但我们不希望这样做。我们试图避免纯粹为了测试而添加代码。您并不是纯粹为了测试而添加属性,而是抽象掉依赖项。因为我不知道你是否在使用IoC框架,所以我只是知道如何使用beach方法。不模拟它不是一个选项,因为测试失败了,出现了对象引用异常。你可以使用MvcContrib项目中的MvcMockHelps,如我的回答所示。HttpContext有数百个依赖项,你应该模拟它们我也会选择MvcMockHelps:-)我已经快速浏览了MvcContrib,虽然我同意它非常有用,但我不知道它在这种情况下如何帮助我。“TestHelper通过提供一个控制器工厂来帮助创建具有正确初始化的内部数据成员的控制器。”我的问题是,我试图在ViewModel中的控制器外部模拟HttpContext。