我在Steve Sanderson's MVC3 book中跟踪了代码示例,其中有一段ControlContext模拟代码,我可以设置表单和查询字符串值。
为了在单元测试中支持TryUpdateModel,我对代码进行了一些更改,例如我已将formValues的数据类型更改为FormCollection formValues
,并添加了以下代码以使其正常工作:
// form Values values setup
this.Request.Setup(x => x.Form).Returns(formValues);
// wire up form with value provider
if (formValues != null)
{
onController.ValueProvider = formValues.ToValueProvider();
}
同时我想对查询字符串集合执行相同的操作,但找不到支持此类函数的等效类。
谁知道如何查询字符串?
答案 0 :(得分:1)
最终,这是我的解决方案
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Moq;
/// <summary>
/// A helper class for MVC projects' unit testing.
/// </summary>
public class ContextMocks
{
/// <summary>
/// Initializes a new instance of the ContextMocks class.
/// </summary>
/// <param name="onController">The controller to mock.</param>
/// <param name="identityName">The fake security identity name for controller.</param>
/// <param name="queryStrings">Fake query string values of the Http context.</param>
/// <param name="formValues">Fake form values of the Http context.</param>
/// <param name="isNewSession">Enables us to mock if the session was created for the current thread or not.</param>
public ContextMocks(Controller onController, string identityName, FormCollection queryStrings, FormCollection formValues, bool isNewSession = true)
{
this.Cookies = new HttpCookieCollection();
this.Request = new Mock<HttpRequestBase>();
this.Response = new Mock<HttpResponseBase>();
this.Server = new Mock<HttpServerUtilityBase>();
// Define all the common context objects, plus relationships between them
this.HttpContext = new Mock<HttpContextBase>();
this.HttpContext.Setup(x => x.Request).Returns(this.Request.Object);
this.HttpContext.Setup(x => x.Response).Returns(this.Response.Object);
this.HttpContext.Setup(x => x.Session).Returns(new FakeSessionState(isNewSession));
this.HttpContext.Setup(x => x.Application).Returns(new FakeApplicationState());
this.HttpContext.Setup(x => x.User.Identity.Name).Returns(identityName);
this.HttpContext.Setup(x => x.Server).Returns(this.Server.Object);
// cookie setup
this.Request.Setup(x => x.Cookies).Returns(this.Cookies);
this.Response.Setup(x => x.Cookies).Returns(this.Cookies);
// query string setup
this.Request.Setup(x => x.QueryString).Returns(queryStrings);
// wire up form with value provider
if (queryStrings != null)
{
onController.ValueProvider = queryStrings.ToValueProvider();
}
// form Values values setup
this.Request.Setup(x => x.Form).Returns(formValues);
// wire up form with value provider
if (formValues != null)
{
onController.ValueProvider = formValues.ToValueProvider();
}
// Apply the mock context to the supplied controller instance
RequestContext rc = new RequestContext(this.HttpContext.Object, new RouteData());
onController.ControllerContext = new ControllerContext(rc, onController);
}
/// <summary>
/// Initializes a new instance of the ContextMocks class. By using this constructor the mock will also enable UrlHelper mocking
/// by using routing table setting.
/// </summary>
/// <param name="onController">The controller to mock.</param>
/// <param name="registerRouteTable">
/// A delegate to the function to register route table.
/// Typically it is MvcApplication.RegisterRoutes function in global.asax.cs.
/// </param>
/// <param name="identityName">The fake security identity name for controller.</param>
/// <param name="queryStrings">Fake query string values of the Http context.</param>
/// <param name="formValues">Fake form values of the Http context.</param>
/// <param name="isNewSession">Enables us to mock if the session was created for the current thread or not.</param>
public ContextMocks(
Controller onController,
Action<RouteCollection> registerRouteTable,
string identityName,
FormCollection queryStrings,
FormCollection formValues,
bool isNewSession = true)
: this(onController, identityName, queryStrings, formValues, isNewSession)
{
this.Response.Setup(x => x.ApplyAppPathModifier(It.IsAny<string>())).Returns<string>(s => s);
// Arrange (get the routing config and test context)
RouteCollection routeConfig = new RouteCollection();
registerRouteTable(routeConfig);
onController.Url = new UrlHelper(new RequestContext(this.HttpContext.Object, new RouteData()), routeConfig);
}
/// <summary>
/// Gets Http Context mock.
/// </summary>
public Mock<HttpContextBase> HttpContext { get; private set; }
/// <summary>
/// Gets Http request mock.
/// </summary>
public Mock<HttpRequestBase> Request { get; private set; }
/// <summary>
/// Gets Http response mock.
/// </summary>
public Mock<HttpResponseBase> Response { get; private set; }
/// <summary>
/// Gets the mock server object.
/// </summary>
public Mock<HttpServerUtilityBase> Server { get; private set; }
/// <summary>
/// Gets Route data.
/// </summary>
public RouteData RouteData { get; private set; }
/// <summary>
/// Gets or sets A collection used to hold fake cookie values.
/// </summary>
private HttpCookieCollection Cookies
{
get;
set;
}
/// <summary>
/// Use queryStringCollectionProvider fake HttpSessionStateBase, because it's hard to mock it with Moq.
/// </summary>
private class FakeSessionState : HttpSessionStateBase
{
/// <summary>
/// Enables us to mock whether the session was created for the current thread or not.
/// </summary>
private bool isNewSession;
/// <summary>
/// Fake session state collection.
/// </summary>
private Dictionary<string, object> items = new Dictionary<string, object>();
/// <summary>
/// Initializes a new instance of the FakeSessionState class.
/// </summary>
/// <param name="isNewSession">Enables us to mock if the session was created for the current thread or not.</param>
public FakeSessionState(bool isNewSession)
{
this.isNewSession = isNewSession;
}
/// <summary>
/// Gets a value that indicates whether the session was created during the current request.
/// </summary>
public override bool IsNewSession
{
get
{
return this.isNewSession;
}
}
/// <summary>
/// An indexer to access the fake session item.
/// </summary>
/// <param name="name">Name of fake session key.</param>
/// <returns>Fake session value.</returns>
public override object this[string name]
{
get { return this.items.ContainsKey(name) ? this.items[name] : null; }
set { this.items[name] = value; }
}
/// <summary>
/// Empties the contents of the session.
/// </summary>
public override void Abandon()
{
this.items = new Dictionary<string, object>();
}
}
/// <summary>
/// Use queryStringCollectionProvider fake HttpApplicationStateBase, because it's hard to mock it with Moq.
/// </summary>
private class FakeApplicationState : HttpApplicationStateBase
{
/// <summary>
/// Fake application state collection.
/// </summary>
private Dictionary<string, object> items = new Dictionary<string, object>();
/// <summary>
/// An indexer to access the fake application item.
/// </summary>
/// <param name="name">Name of fake application key.</param>
/// <returns>Fake application value.</returns>
public override object this[string name]
{
get { return this.items.ContainsKey(name) ? this.items[name] : null; }
set { this.items[name] = value; }
}
/// <summary>
/// Mock out of the lock method.
/// </summary>
public override void Lock()
{
}
/// <summary>
/// Mock out of the unlock method.
/// </summary>
public override void UnLock()
{
}
/// <summary>
/// Adds the fake object to the application object.
/// </summary>
/// <param name="name">The key</param>
/// <param name="value">The value being added in conjunction with the key.</param>
public override void Add(string name, object value)
{
this.items.Add(name, value);
}
}
}