HttpContext,HttpRequest,HttpResponse等已經有了「包裝器」類.MVC框架使用這些類,你可以通過控制器上下文將它們提供給控制器。您不需要模擬控制器上下文,因爲您可以簡單地使用適當的值創建控制器上下文。我發現唯一難以嘲笑的是幫手,UrlHelper和HtmlHelper。那些有一些相對較深的依賴性。你可以用一種合理的方式僞造它們,UrlHelper如下所示。
var httpContext = MockRepository.GenerateMock<HttpContextBase>();
var routeData = new RoutedData();
var controller = new HomeController();
controller.ControllerContext = new ControllerContext(httpContext, routeData, controller);
controller.Url = UrlHelperFactory.CreateUrlHelper(httpContext, routeDate);
其中
public static class UrlHelperFactory
{
public static UrlHelper CreateUrlHelper(HttpContextBase httpContext, RouteData routeData)
{
return CreateUrlHelper(httpContext, routeData, "/");
}
public static UrlHelper CreateUrlHelper(HttpContextBase httpContext, RouteData routeData, string url)
{
string urlString = string.Format("http://localhost/{0}/{1}/{2}", routeData.Values["controller"], routeData.Values["action"], routeData.Values["id"]).TrimEnd('/');
var uri = new Uri(urlString);
if (httpContext.Request == null)
{
httpContext.Stub(c => c.Request).Return(MockRepository.GenerateStub<HttpRequestBase>()).Repeat.Any();
}
httpContext.Request.Stub(r => r.Url).Return(uri).Repeat.Any();
httpContext.Request.Stub(r => r.ApplicationPath).Return("/").Repeat.Any();
if (httpContext.Response == null)
{
httpContext.Stub(c => c.Response).Return(MockRepository.GenerateStub<HttpResponseBase>()).Repeat.Any();
}
if (url != "/")
{
url = url.TrimEnd('/');
}
httpContext.Response.Stub(r => r.ApplyAppPathModifier(Arg<string>.Is.Anything)).Return(url).Repeat.Any();
return new UrlHelper(CreateRequestContext(httpContext, routeData), GetRoutes());
}
public static RequestContext CreateRequestContext(HttpContextBase httpContext, RouteData routeData)
{
return new RequestContext(httpContext, routeData);
}
// repeat your route definitions here!!!
public static RouteCollection GetRoutes()
{
RouteCollection routes = new RouteCollection();
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "home", action = "index", id = "" } // Parameter defaults
);
return routes;
}
}
權,這將是選項4,和HttpContextBase這僅適用。正如你所展示的那樣,我可以抽象出這個測試設置代碼,但是這不包括像ConfigurationManager等其他靜態類,所以你最終得到了解決同一問題的兩種解決方案,而選項1或2將它們統一起來。正如我所說,他們是兩種不同的解決方案,我假設你更喜歡在這裏使用選項4 ... –
除了你沒有提供一個模擬控制器上下文,而是一個實際的控制器上下文與嵌入的相關模擬。我使用構造函數注入來處理FormsAuthentication,MembershipProvider等事情,並使用適當的包裝器,儘管我只在我的AccountController上使用這些構造器注入。對於其他東西,我嘲笑通過HttpContext,如請求,響應,用戶,會話等。 – tvanfosson
Doh!我原來的帖子裏寫錯了,錯誤。這就是我想說的。現在修復。對於爲什麼你喜歡這種方法而不是將對象作爲一個整體進行封裝(選項1)還是部分按角色(選項2),或者我用「正在注入的很多依賴項正在快速增長」的方式來實現它的評論? –