zoukankan      html  css  js  c++  java
  • Mock session,cookie,querystring in ASB.NET MVC

      写测试用例的时候经常发现,所写的功能需要Http上下文的支持(session,cookie)这类的.

      以下介绍2种应用场景.

    用于控制器内Requet获取参数

      控制器内的Requet其实是控制器内的属性.那么在mock的时候把那些上下文附加到Controller里的控制器上下文(ControllerContext )里,request自然就有东西了.


    public Controller() { /// <summary> /// 获取或设置控制器上下文。 /// </summary> /// /// <returns> /// 控制器上下文。 /// </returns> public ControllerContext ControllerContext { get; set; } /// <summary> /// 为当前 HTTP 请求获取 HttpRequestBase 对象。 /// </summary> /// /// <returns> /// 请求对象。 /// </returns> public HttpRequestBase Request { get { if (this.HttpContext != null) return this.HttpContext.Request; return (HttpRequestBase) null; } } }

      

    为此,为了单独的Mock这些http上下文中的一些元素,我们需要6个类

    Mock类

        //http://stephenwalther.com/archive/2008/07/01/asp-net-mvc-tip-12-faking-the-controller-context
        public class FakeControllerContext : ControllerContext
        {
            //public FakeControllerContext(ControllerBase controller)
            //    : this(controller, null, null, null, null, null, null)
            //{
            //}
    
            /// <summary>
            /// MockCookie
            /// </summary>
            /// <param name="controller"></param>
            /// <param name="cookies"></param>
            public FakeControllerContext(ControllerBase controller, HttpCookieCollection cookies)
                : this(controller, null, null, null, null, cookies, null)
            {
            }
    
            /// <summary>
            /// MockSession
            /// </summary>
            /// <param name="controller"></param>
            /// <param name="sessionItems"></param>
            public FakeControllerContext(ControllerBase controller, SessionStateItemCollection sessionItems)
                : this(controller, null, null, null, null, null, sessionItems)
            {
            }
    
            /// <summary>
            /// MockForm
            /// </summary>
            /// <param name="controller"></param>
            /// <param name="formParams"></param>
            public FakeControllerContext(ControllerBase controller, NameValueCollection formParams)
                : this(controller, null, null, formParams, null, null, null)
            {
            }
    
            /// <summary>
            /// MockForm+QueryString
            /// </summary>
            /// <param name="controller"></param>
            /// <param name="formParams"></param>
            /// <param name="queryStringParams"></param>
            public FakeControllerContext(ControllerBase controller, NameValueCollection formParams, NameValueCollection queryStringParams)
                : this(controller, null, null, formParams, queryStringParams, null, null)
            {
            }
    
    
    
            public FakeControllerContext(ControllerBase controller, string userName)
                : this(controller, userName, null, null, null, null, null)
            {
            }
    
    
            public FakeControllerContext(ControllerBase controller, string userName, string[] roles)
                : this(controller, userName, roles, null, null, null, null)
            {
            }
    
            /// <summary>
            /// Mock Session+Cookie+Form+QuertyString+IIdentity
            /// </summary>
            /// <param name="controller">控制器名</param>
            /// <param name="userName"></param>
            /// <param name="roles"></param>
            /// <param name="formParams">Form</param>
            /// <param name="queryStringParams">QueryString</param>
            /// <param name="cookies">Cookie</param>
            /// <param name="sessionItems">Session</param>
            public FakeControllerContext
                (
                    ControllerBase controller,
                    string userName,
                    string[] roles,
                    NameValueCollection formParams,
                    NameValueCollection queryStringParams,
                    HttpCookieCollection cookies,
                    SessionStateItemCollection sessionItems
                )
                : base(new FakeHttpContext(
                    new FakePrincipal(new FakeIdentity(userName), roles),
                    formParams,
                    queryStringParams,
                    cookies, sessionItems), new RouteData(), controller)
            { }
    
            /// <summary>
            /// 
            /// </summary>
            /// <param name="controller"></param>
            /// <param name="formParams"></param>
            /// <param name="queryStringParams"></param>
            /// <param name="cookies"></param>
            /// <param name="sessionItems"></param>
            /// <param name="userName"></param>
            /// <param name="roles"></param>
            public FakeControllerContext
        (
            ControllerBase controller,
            NameValueCollection formParams,
            NameValueCollection queryStringParams,
            HttpCookieCollection cookies,
            SessionStateItemCollection sessionItems,
                  string userName = null,
            string[] roles = null
        )
                : base(new FakeHttpContext(
                    new FakePrincipal(new FakeIdentity(userName), roles),
                    formParams,
                    queryStringParams,
                    cookies, sessionItems), new RouteData(), controller)
            { }
        }
    
        public class FakeHttpContext : HttpContextBase
        {
            private readonly FakePrincipal _principal;
            private readonly NameValueCollection _formParams;
            private readonly NameValueCollection _queryStringParams;
            private readonly HttpCookieCollection _cookies;
            private readonly SessionStateItemCollection _sessionItems;
    
    
            public FakeHttpContext(FakePrincipal principal, NameValueCollection formParams, NameValueCollection queryStringParams, HttpCookieCollection cookies, SessionStateItemCollection sessionItems)
            {
                _principal = principal;
                _formParams = formParams;
                _queryStringParams = queryStringParams;
                _cookies = cookies;
                _sessionItems = sessionItems;
            }
    
            public override HttpRequestBase Request { get { return new FakeHttpRequest(_formParams, _queryStringParams, _cookies); } }
    
            public override IPrincipal User { get { return _principal; } set { throw new System.NotImplementedException(); } }
            public override HttpSessionStateBase Session { get { return new FakeHttpSessionState(_sessionItems); } }
        }
    
      public class FakeHttpRequest : HttpRequestBase
        {
            private readonly NameValueCollection _formParams;
            private readonly NameValueCollection _queryStringParams;
            private readonly HttpCookieCollection _cookies;
    
            public FakeHttpRequest(NameValueCollection formParams, NameValueCollection queryStringParams, HttpCookieCollection cookies)
            {
                _formParams = formParams;
                _queryStringParams = queryStringParams;
                _cookies = cookies;
            }
    
            public override NameValueCollection Form
            {
                get
                {
                    return _formParams;
                }
            }
    
            public override NameValueCollection QueryString
            {
                get
                {
                    return _queryStringParams;
                }
            }
    
            public override HttpCookieCollection Cookies
            {
                get
                {
                    return _cookies;
                }
            }
    
        }
    
      public class FakeHttpSessionState : HttpSessionStateBase
        {
            private readonly SessionStateItemCollection _sessionItems;
    
            public FakeHttpSessionState(SessionStateItemCollection sessionItems)
            {
                _sessionItems = sessionItems;
            }
    
            public override void Add(string name, object value)
            {
                _sessionItems[name] = value;
            }
    
            public override int Count
            {
                get
                {
                    return _sessionItems.Count;
                }
            }
    
            public override IEnumerator GetEnumerator()
            {
                return _sessionItems.GetEnumerator();
            }
    
            public override NameObjectCollectionBase.KeysCollection Keys
            {
                get
                {
                    return _sessionItems.Keys;
                }
            }
    
            public override object this[string name]
            {
                get
                {
                    return _sessionItems[name];
                }
                set
                {
                    _sessionItems[name] = value;
                }
            }
    
            public override object this[int index]
            {
                get
                {
                    return _sessionItems[index];
                }
                set
                {
                    _sessionItems[index] = value;
                }
            }
    
            public override void Remove(string name)
            {
                _sessionItems.Remove(name);
            }
        }
    
       
        public class FakeIdentity : IIdentity
        {
            private readonly string _name;
    
            public FakeIdentity(string userName) { _name = userName; }
    
            public string AuthenticationType { get { throw new System.NotImplementedException(); } }
    
            public bool IsAuthenticated { get { return !String.IsNullOrEmpty(_name); } }
    
            public string Name { get { return _name; } }
    
        }
    
        public class FakePrincipal : IPrincipal
        {
            private readonly IIdentity _identity;
            private readonly string[] _roles;
    
            public FakePrincipal(IIdentity identity, string[] roles)
            {
                _identity = identity;
                _roles = roles;
            }
    
            public IIdentity Identity { get { return _identity; } }
    
            public bool IsInRole(string role)
            {
                if (_roles == null)
                    return false;
                return _roles.Contains(role);
            }
        }
    

      在原示例里面那个外国佬还mock了其他东西( IPrincipal User).但对于我来说没这方面需求.

      然后我们测试一下.

    测试控制器

      public class TestController : Controller
        {
            #region 请求模拟输出
            public ActionResult TestSession()
            {
                return Content(Session["hehe"].ToString());
            }
    
    
            public ActionResult TestCookie()
            {
                var cookie = Request.Cookies["hehe"];
                if (cookie == null)
                    return new EmptyResult();
                return Content(cookie.Values["c1"]);
            }
    
            #endregion
    
            #region 请求测试
            public ActionResult TestForm()
            {
                string fuckyou = Request.Form["fuckyou"];
                if (fuckyou == null)
                    return new EmptyResult();
                return Content(fuckyou);
            }
    
            public ActionResult TestFormAndQueryString()
            {
                string form = Request.Form["fuckyou"];
                string querty = Request.QueryString["fuckyou2"];
                return Content(form + "," + querty);
            }
    
            public ActionResult TestMuilt()
            {
                var session = Session["hehe"].ToString();
                var cookie = Request.Cookies["hehe"].Values["c1"];
                string fuckyou = Request.Form["fuckyou"];
                string querty = Request.QueryString["fuckyou2"];
                return Content(string.Format("{1} {0} {2} {0}{3} {0} {4} {0}", Environment.NewLine, session, cookie, fuckyou, querty));
            }
            #endregion
    
      }
    

      测试类

        [TestClass]
        public class MockRequestTest
        {
            private readonly IUserCenterService _IUserCenterService;
            public MockRequestTest()
            {
                EngineContext.Initialize(false);
                _IUserCenterService = EngineContext.Current.Resolve<IUserCenterService>();
            }
    
            [Test]
            [TestMethod]
            public void MockSession()
            {
                //_IUserCenterService = EngineContext.Current.Resolve<IUserCenterService>();
                var controller = new TestController();
                var sessionItems = new SessionStateItemCollection();
                sessionItems["hehe"] = 23;
                controller.ControllerContext = new FakeControllerContext(controller, sessionItems);
                var result = controller.TestSession() as ContentResult;
                Assert.AreEqual(result.Content, "23");
            }
    
            [TestMethod]
            public void MockCookie()
            {
                var controller = new TestController();
                var mockCookie = new HttpCookie("hehe");
                mockCookie["c1"] = "nima1";
                mockCookie["c2"] = "nima2";
                var requestCookie = new HttpCookieCollection() { { mockCookie } };
                controller.ControllerContext = new FakeControllerContext(controller, requestCookie);
                var result = controller.TestCookie() as ContentResult;
                Console.WriteLine(HttpContext.Current == null);
                Assert.AreEqual("nima1", result.Content);
            }
    
            /// <summary>
            /// MockForm
            /// </summary>
            [TestMethod]
            public void MockForm()
            {
                var controller = new TestController();
                NameValueCollection form = new FormCollection()
                {
                    {"fuckyou","1"},
                    {"fuckyou","2"},
                };
                controller.ControllerContext = new FakeControllerContext(controller, form);
                var result = controller.TestForm() as ContentResult;
                Debug.Assert(false, result.Content);
                Assert.IsNotNull(result.Content);
            }
    
            /// <summary>
            /// MockForm
            /// </summary>
            [TestMethod]
            public void MockFormAndQueryString()
            {
                var controller = new TestController();
                NameValueCollection form = new FormCollection()
                {
                    {"fuckyou","1"},
                    {"fuckyou2","2"},
                };
                controller.ControllerContext = new FakeControllerContext(controller, form, form);
                var result = controller.TestFormAndQueryString() as ContentResult;
                //Debug.Assert(false, result.Content);
                Assert.AreEqual("1,2", result.Content);
            }
    
            /// <summary>
            /// Mock Session+Cookie+Form+QuertyString
            /// </summary>
            [TestMethod]
            public void MockMuilt()
            {
                var controller = new TestController();
                var sessionItems = new SessionStateItemCollection();
                sessionItems["hehe"] = 23;
    
                var mockCookie = new HttpCookie("hehe");
                mockCookie["c1"] = "nima1";
                mockCookie["c2"] = "nima2";
                var requestCookie = new HttpCookieCollection() { { mockCookie } };
    
                NameValueCollection form = new FormCollection()
                {
                    {"fuckyou","1"},
                    {"fuckyou2","2"},
                };
    
                controller.ControllerContext = new FakeControllerContext(controller, form, form, requestCookie, sessionItems);
                var result = controller.TestMuilt() as ContentResult;
                Debug.Assert(
                    false,
                    result.Content,
                    string.Format("正确的结果顺序应该是{0};{1};{2};{3};", sessionItems[0], mockCookie["c1"], form["fuckyou"], form["fuckyou2"])
                    );
            }
        }
    

      在上面这个MS测试用例里,我分别测试了

    • Mock session
    • Mock cookie
    • Mock表单
    • Mock 表单+querystring
    • Mock session+cookie+表单+querystring

      都是通过的.

    但是这样有个问题.

    问题就是:然而这并没有什么卵用.

    mock HttpContext.Current

      实际开发的时候.控制器基本打酱油,别的层面需要获取上下文是从HttpContext.Current.Request中获取.如果在刚才的测试用例.控制器输出的是HttpContext.Current.Request.这玩意无疑是null的.因为我们只是把上下文赋值到控制器里的http上下文里面,和HttpContext.Current.Reques是不同的一个概念.

      所以呢,我们需要mock 和HttpContext.Current.Request.

      session的话,比较容易,那就是

    SessionStateUtility.AddHttpSessionStateToContext
    

      cookie的话比较麻烦.HttpRequest.Cookies是一个只读属性,就算用反射赋值也会失败.这里我比较取巧,只用了cookie集合的第一个.有多个的话,可能得把方法改得更恶心一点吧.

    代码

      public static class WebExtension
        {
            /// <summary>
            /// 伪造session
            /// </summary>
            /// <param name="url"></param>
            /// <param name="sesion"></param>
            /// <param name="queryString"></param>
            /// <param name="requesttype"></param>
            public static void FakeHttpContext(this string url, SessionStateItemCollection sesion, string queryString = null, string requesttype = null, HttpCookieCollection cookie = null)
            {
                var stringWriter = new StringWriter();
                var httpResponce = new HttpResponse(stringWriter);
                HttpRequest request;
                if (cookie == null)
                {
                    request = new HttpRequest(string.Empty, url, queryString ?? string.Empty)
                   {
                       RequestType = requesttype ?? "GET",
                   };
                }
                else
                {
                    request = new HttpRequest(string.Empty, url, queryString ?? string.Empty)
                    {
                        RequestType = requesttype ?? "GET",
                        Cookies = { cookie[0] },
                    };
                }
                var httpContext = new HttpContext(request, httpResponce);
                if (sesion != null)
                {
                    SessionStateUtility.AddHttpSessionStateToContext(httpContext,
                   new HttpSessionStateContainer(SessionNameStorage.Suser,
                                 sesion,
                                 new HttpStaticObjectsCollection(),
                                 20000,
                                 true,
                                 HttpCookieMode.AutoDetect,
                                 SessionStateMode.InProc,
                                 false
                             ));
                }
                if (cookie != null)
                {
                    //无法对只读属性赋值,会导致异常
                    //Type ret = typeof(HttpRequest);
                    //PropertyInfo pr = ret.GetProperty("Cookies");
                    //pr.SetValue(request, cookie, null); //赋值属性
    
                }
    
                //var sessionContainer = new HttpSessionStateContainer(
                //    "id",
                //    new SessionStateItemCollection(),
                //    new HttpStaticObjectsCollection(),
                //    10,
                //    true,
                //    HttpCookieMode.AutoDetect,
                //    SessionStateMode.InProc,
                //    false);
    
                //httpContext.Items["AspSession"] =
                //    typeof(HttpSessionState).GetConstructor(
                //        BindingFlags.NonPublic | BindingFlags.Instance,
                //        null,
                //        CallingConventions.Standard,
                //        new[] { typeof(HttpSessionStateContainer) },
                //        null).Invoke(new object[] { sessionContainer });
    
                HttpContext.Current = httpContext;
            }
    
    
    
    
    
        }
    

      

    相应控制器以及测试用例

            public ActionResult TestHttpCurrent()
            {
                var a = System.Web.HttpContext.Current;
                if (a != null)
                {
                    return Content(a.Request.Cookies.Get("hehe").Value);
                }
                return Content("");
            }
    
            [TestMethod]
            public void httpCurrent()
            {
                var controller = new TestController();
                var mockCookie = new HttpCookie("hehe");
                mockCookie["c1"] = "nima1";
                mockCookie["c2"] = "nima2";
                var requestCookie = new HttpCookieCollection() { { mockCookie } };
                string.Format("{0}/test/TestHttpCurrent", TestHelper.WebRootUrl).FakeHttpContext(sesion: null, cookie: requestCookie);
                var result = controller.TestHttpCurrent() as ContentResult;
                Console.WriteLine(result.Content);
    
            }
    

      session就不测了,我平时测试的时候试了无数次都是有的.

    备注:

    mock cookie那里,如果有更好的实现方式,请告诉我.

    标题是故意为之的,代表了我对ASB.NET 的嘲讽.

    参考链接:

    ASP.NET MVC Tip #12 – Faking the Controller Context

    
    

    ASP.NET MVC, HttpContext.Current is null while mocking a request

  • 相关阅读:
    【译】.NET 的新的动态检测分析
    【译】Visual Studio 的 Razor 编辑器的改进
    【译】.NET 5. 0 中 Windows Form 的新特性
    MySQL InnoDB 索引(Index)
    MySQL 全文检索(Full-Text Search)
    MySQL 计算最大值、最小值和中位数
    MySQL 触发器(Triggers)
    MySQL 视图(View)
    MySQL基础知识:MySQL String 字符串处理
    MySQL基础知识:MySQL Connection和Session
  • 原文地址:https://www.cnblogs.com/zeusro/p/4556462.html
Copyright © 2011-2022 走看看