0

我跟着代碼示例在Steve Sanderson's MVC3 book,有一塊ControlContext模擬代碼那裏我可以設置窗體和查詢字符串值。模仿MVC3 ControllerContext查詢字符串集合和ValueProvider

爲了支持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

喜 - 你發現這一點?謝謝 – andrew 2012-09-18 09:59:51

+0

是的,請在下面看到我自己的答案。 – hardywang 2012-09-18 18:37:30

回答

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); 
     } 
    } 
} 
+0

感謝您的信息 – andrew 2012-09-19 00:55:25