• 含有HttpContext元素的单元测试


        我们在开发WEB项目的时候,一般应用逻辑跟ASPX页面是分离的项目。应用逻辑一般会是一个DLL组件项目。如果这个组件项目中A方法使用了Session、Cookie等信息的读写,则这个方法就很难写单元测试。
      但并不是写不出来,要写出来大致思路如下:

      目标:
      构建一个测试的环境,把需要的Session、Cookie等信息初始化好。 这样才好做测试。而且这个构建的环境,不应该影响实际功能代码的编写。

      具体实现来说:

      我们要使用Mock技术,但就HttpContext来言,直接mock这个对象会有一个问题,它不具备Session的功能。这时候我们就需要用 Mock 技术来构造一个可以满足我们需要的环境的原理:这个Mock的机制如下:

      用反射机制,构造一个 HttpSessionState 对象(HttpSessionState类的构造函数是internal 的),然后把这个对象跟SimpleWorkerRequest 对象捆绑。

    这样我们就可以 构建了一个满足自己需要的环境了,即 TestHttpContext 类。

      以下是两个类的实现:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Web.SessionState;
    using System.Web;
    using System.Threading;
    using System.Globalization;
    using System.Collections.Specialized;
    using System.Collections;
    using System.IO;
    using System.Web.Hosting;
    using System.Reflection;

    namespace TestNamespace
    {
       public class TestHttpContext
        {
            private const string ContextKeyAspSession = "AspSession";
            private HttpContext context = null;
            private TestHttpContext() : base() { }
            public TestHttpContext(bool isSecure)
                : this()
            {
                MySessionState myState = new MySessionState(Guid.NewGuid().ToString("N"),
                    new SessionStateItemCollection(), new HttpStaticObjectsCollection(),
                    5, true, HttpCookieMode.UseUri, SessionStateMode.InProc, false);

                TextWriter tw = new StringWriter();
                HttpWorkerRequest wr = new SimpleWorkerRequest("/webapp", "c:\\inetpub\\wwwroot\\webapp\\", "default.aspx", "", tw);
                this.context = new HttpContext(wr);
                HttpSessionState state = Activator.CreateInstance(
                    typeof(HttpSessionState),
                    BindingFlags.Public | BindingFlags.NonPublic |
                    BindingFlags.Instance | BindingFlags.CreateInstance,
                    null,
                    new object[] { myState },
                    CultureInfo.CurrentCulture) as HttpSessionState;
                this.context.Items[ContextKeyAspSession] = state;
                HttpContext.Current = this.context;
            }

            public HttpContext Context
            {
                get
                {
                    return this.context;
                }
            }

            private class WorkerRequest : SimpleWorkerRequest
            {
                private bool isSecure = false;
                public WorkerRequest(string page, string query, TextWriter output, bool isSecure)
                    : base(page, query, output)
                {
                    this.isSecure = isSecure;
                }

                public override bool IsSecure()
                {
                    return this.isSecure;
                }
            }
        }
        public sealed class MySessionState : IHttpSessionState
        {
            const int MAX_TIMEOUT = 24 * 60;  // Timeout cannot exceed 24 hours.

            string pId;
            ISessionStateItemCollection pSessionItems;
            HttpStaticObjectsCollection pStaticObjects;
            int pTimeout;
            bool pNewSession;
            HttpCookieMode pCookieMode;
            SessionStateMode pMode;
            bool pAbandon;
            bool pIsReadonly;

            public MySessionState(string id,
                                  ISessionStateItemCollection sessionItems,
                                  HttpStaticObjectsCollection staticObjects,
                                  int timeout,
                                  bool newSession,
                                  HttpCookieMode cookieMode,
                                  SessionStateMode mode,
                                  bool isReadonly)
            {
                pId = id;
                pSessionItems = sessionItems;
                pStaticObjects = staticObjects;
                pTimeout = timeout;
                pNewSession = newSession;
                pCookieMode = cookieMode;
                pMode = mode;
                pIsReadonly = isReadonly;
            }


            public int Timeout
            {
                get { return pTimeout; }
                set
                {
                    if (value <= 0)
                        throw new ArgumentException("Timeout value must be greater than zero.");

                    if (value > MAX_TIMEOUT)
                        throw new ArgumentException("Timout cannot be greater than " + MAX_TIMEOUT.ToString());

                    pTimeout = value;
                }
            }


            public string SessionID
            {
                get { return pId; }
            }


            public bool IsNewSession
            {
                get { return pNewSession; }
            }


            public SessionStateMode Mode
            {
                get { return pMode; }
            }


            public bool IsCookieless
            {
                get { return CookieMode == HttpCookieMode.UseUri; }
            }


            public HttpCookieMode CookieMode
            {
                get { return pCookieMode; }
            }


            //
            // Abandon marks the session as abandoned. The IsAbandoned property is used by the
            // session state module to perform the abandon work during the ReleaseRequestState event.
            //
            public void Abandon()
            {
                pAbandon = true;
            }

            public bool IsAbandoned
            {
                get { return pAbandon; }
            }

            //
            // Session.LCID exists only to support legacy ASP compatibility. ASP.NET developers should use
            // Page.LCID instead.
            //
            public int LCID
            {
                get { return Thread.CurrentThread.CurrentCulture.LCID; }
                set { Thread.CurrentThread.CurrentCulture = CultureInfo.ReadOnly(new CultureInfo(value)); }
            }


            //
            // Session.CodePage exists only to support legacy ASP compatibility. ASP.NET developers should use
            // Response.ContentEncoding instead.
            //
            public int CodePage
            {
                get
                {
                    if (HttpContext.Current != null)
                        return HttpContext.Current.Response.ContentEncoding.CodePage;
                    else
                        return Encoding.Default.CodePage;
                }
                set
                {
                    if (HttpContext.Current != null)
                        HttpContext.Current.Response.ContentEncoding = Encoding.GetEncoding(value);
                }
            }


            public HttpStaticObjectsCollection StaticObjects
            {
                get { return pStaticObjects; }
            }


            public object this[string name]
            {
                get { return pSessionItems[name]; }
                set { pSessionItems[name] = value; }
            }


            public object this[int index]
            {
                get { return pSessionItems[index]; }
                set { pSessionItems[index] = value; }
            }


            public void Add(string name, object value)
            {
                pSessionItems[name] = value;
            }


            public void Remove(string name)
            {
                pSessionItems.Remove(name);
            }


            public void RemoveAt(int index)
            {
                pSessionItems.RemoveAt(index);
            }


            public void Clear()
            {
                pSessionItems.Clear();
            }

            public void RemoveAll()
            {
                Clear();
            }

            public int Count
            {
                get { return pSessionItems.Count; }
            }

            public NameObjectCollectionBase.KeysCollection Keys
            {
                get { return pSessionItems.Keys; }
            }


            public IEnumerator GetEnumerator()
            {
                return pSessionItems.GetEnumerator();
            }


            public void CopyTo(Array items, int index)
            {
                foreach (object o in items)
                    items.SetValue(o, index++);
            }


            public object SyncRoot
            {
                get { return this; }
            }


            public bool IsReadOnly
            {
                get { return pIsReadonly; }
            }


            public bool IsSynchronized
            {
                get { return false; }
            }

        }

    }

    这样我们在进行单元测试时就可以Mock掉Web下的Session,Cookie等对象。

    例如:

    [TestMethod()]
    public void TestGetUserId()
    {
        TestHttpContext mock = new TestHttpContext(false);
        System.Web.HttpContext context = mock.Context;
        context.Session["UserId"] = 1245;

        Assert.AreEqual(long.Parse(context.Session["UserId"].ToString()), 1245, "读取用户ID错误!");
    }

  • 相关阅读:
    怎样搭建PHP开发环境
    求教Sublime Text2 SublimeLinter插件安装问题
    借助 SublimeLinter 编写高质量的 JavaScript & CSS 代码
    sublime 支持php语法错误提示的插件
    sublime text 2 配置php调试环境
    解决file_get_contents无法请求https连接的方法
    JavaSE(六)包装类、基本类型和字符串之间的转换、==和equals的区别
    JavaSE(五)JAVA对象向上转型和向下转型
    JavaSE(四)之接口、访问控制
    JavaSE(二)之继承、封装、多态
  • 原文地址:https://www.cnblogs.com/wangjq/p/1854297.html
Copyright © 2020-2023  润新知