我的 MVC4 Web 应用程序中有某些控制器操作,它们使用 Response 对象来访问查询字符串变量等。将其抽象化以使其不干扰单元测试操作的最佳实践是什么?
问问题
552 次
1 回答
5
MVC4 团队已经将HttpContext
相关属性抽象化,以便可以模拟它们,所以Response
现在是类型HttpResponseBase
,所以已经被抽象掉了。你可以模拟对它的调用。
下面是我过去在单元测试场景中用于初始化控制器的标准方法。这是关于最小起订量。我创建了一个假的 http 上下文,它根据需要模拟出各种相关的属性。您可以修改它以适合您的确切情况。
在实例化控制器之后,我将它传递给这个方法(也许在一个基类中 - 我使用 NBehave 进行单元测试,但我不会在这里专门与任何相关的东西混淆水域):
protected void InitialiseController(T controller, NameValueCollection collection, params string[] routePaths)
{
Controller = controller;
var routes = new RouteCollection();
RouteConfig.RegisterRoutes(routes);
var httpContext = ContextHelper.FakeHttpContext(RelativePath, AbsolutePath, routePaths);
var context = new ControllerContext(new RequestContext(httpContext, new RouteData()), Controller);
var urlHelper = new UrlHelper(new RequestContext(httpContext, new RouteData()), routes);
Controller.ControllerContext = context;
Controller.ValueProvider = new NameValueCollectionValueProvider(collection, CultureInfo.CurrentCulture);
Controller.Url = urlHelper;
}
这ContextHelper
是所有模拟设置的地方:
public static class ContextHelper
{
public static HttpContextBase FakeHttpContext(string relativePath, string absolutePath, params string[] routePaths)
{
var httpContext = 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();
httpContext.Setup(x => x.Server).Returns(server.Object);
httpContext.Setup(x => x.Session).Returns(session.Object);
httpContext.Setup(x => x.Request).Returns(request.Object);
httpContext.Setup(x => x.Response).Returns(response.Object);
response.Setup(x => x.Cookies).Returns(cookies);
httpContext.SetupGet(x => x.Request.Url).Returns(new Uri("http://localhost:300"));
httpContext.SetupGet(x => x.Request.UserHostAddress).Returns("127.0.0.1");
if (!String.IsNullOrEmpty(relativePath))
{
server.Setup(x => x.MapPath(relativePath)).Returns(absolutePath);
}
// used for matching routes within calls to Url.Action
foreach (var path in routePaths)
{
var localPath = path;
response.Setup(x => x.ApplyAppPathModifier(localPath)).Returns(localPath);
}
var writer = new StringWriter();
var wr = new SimpleWorkerRequest("", "", "", "", writer);
HttpContext.Current = new HttpContext(wr);
return httpContext.Object;
}
}
我最近写了一篇博客文章,介绍了这种方法,但Nsubstitute
用作模拟框架而不是MOQ
:
于 2013-04-01T22:02:32.287 回答