Mock session,cookie,querystring in ASB.NET MVC

简介:   写测试用例的时候经常发现,所写的功能需要Http上下文的支持(session,cookie)这类的.   以下介绍2种应用场景. 用于控制器内Requet获取参数   控制器内的Requet其实是控制器内的属性.那么在mock的时候把那些上下文附加到Controller里的控制器上下文(ControllerContext )里,request自然就有东西了. public Controller() { /// /// 获取或设置控制器上下文。

  写测试用例的时候经常发现,所写的功能需要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

 

目录
相关文章
|
27天前
|
缓存 Java Spring
servlet和SpringBoot两种方式分别获取Cookie和Session方式比较(带源码) —— 图文并茂 两种方式获取Header
文章比较了在Servlet和Spring Boot中获取Cookie、Session和Header的方法,并提供了相应的代码实例,展示了两种方式在实际应用中的异同。
104 3
servlet和SpringBoot两种方式分别获取Cookie和Session方式比较(带源码) —— 图文并茂 两种方式获取Header
|
10天前
|
存储 安全 数据安全/隐私保护
Cookie 和 Session 的区别及使用 Session 进行身份验证的方法
【10月更文挑战第12天】总之,Cookie 和 Session 各有特点,在不同的场景中发挥着不同的作用。使用 Session 进行身份验证是常见的做法,通过合理的设计和管理,可以确保用户身份的安全和可靠验证。
12 1
|
2月前
|
存储 缓存 数据处理
php学习笔记-php会话控制,cookie,session的使用,cookie自动登录和session 图书上传信息添加和修改例子-day07
本文介绍了PHP会话控制及Web常用的预定义变量,包括`$_REQUEST`、`$_SERVER`、`$_COOKIE`和`$_SESSION`的用法和示例。涵盖了cookie的创建、使用、删除以及session的工作原理和使用,并通过图书上传的例子演示了session在实际应用中的使用。
php学习笔记-php会话控制,cookie,session的使用,cookie自动登录和session 图书上传信息添加和修改例子-day07
|
2月前
|
开发框架 前端开发 JavaScript
ASP.NET MVC 教程
ASP.NET 是一个使用 HTML、CSS、JavaScript 和服务器脚本创建网页和网站的开发框架。
35 7
|
2月前
|
存储 前端开发 Java
JavaWeb基础7——会话技术Cookie&Session
会话技术、Cookie的发送和获取、存活时间、Session钝化与活化、销毁、用户登录注册“记住我”和“验证码”案例
JavaWeb基础7——会话技术Cookie&Session
|
2月前
|
存储 安全 NoSQL
Cookie、Session、Token 解析
Cookie、Session、Token 解析
49 0
|
2月前
|
存储 JSON 数据安全/隐私保护
Cookie + Session 的时代已经过去了?
在探讨“Cookie + Session”这一经典组合是否已经过时的议题时,我们首先需要理解它们在Web应用认证和会话管理中的历史地位与当前面临的挑战。随着Web技术的飞速发展,特别是无状态服务、OAuth、JWT(JSON Web Tokens)等技术的兴起,这一传统机制确实面临了前所未有的变革压力。但说它“完全过去”或许过于绝对,因为它在特定场景下仍发挥着重要作用。
33 0
|
3月前
|
存储 JavaScript 前端开发
Cookie 反制策略详解:Cookie加解密原理、Cookie和Session机制、Cookie hook、acw_sc__v2、jsl Cookie调试、重定向Cookie
Cookie 反制策略详解:Cookie加解密原理、Cookie和Session机制、Cookie hook、acw_sc__v2、jsl Cookie调试、重定向Cookie
143 1
|
3月前
|
存储 安全 搜索推荐
【JavaWeb 秘籍】Cookie vs Session:揭秘 Web 会话管理的奥秘与实战指南!
【8月更文挑战第24天】本文以问答形式深入探讨了Web开发中关键的会话管理技术——Cookie与Session。首先解释了两者的基本概念及工作原理,随后对比分析了它们在存储位置、安全性及容量上的差异。接着,通过示例代码详细介绍了如何在JavaWeb环境中实现Cookie与Session的操作,包括创建与读取过程。最后,针对不同应用场景提供了选择使用Cookie或Session的指导建议,并提出了保障二者安全性的措施。阅读本文可帮助开发者更好地理解并应用这两种技术。
50 1
|
3月前
|
存储 安全 搜索推荐
深入探讨Session和Cookie的概念、用途以及如何在Java Web开发中有效地使用它们进行用户状态管理。
在Java Web开发中,Session和Cookie是管理用户状态的核心技术。Session存储于服务器端,通过唯一的Session ID识别用户,确保数据安全与隐私;Cookie则存储于客户端,用于记录用户偏好等信息。两者各有优势:Session适合存储敏感数据,但需合理管理避免资源浪费;Cookie便于持久化存储,但在安全性上需谨慎设置。开发者可通过Servlet API轻松操作二者,实现个性化用户体验与应用性能优化。
54 2