含有HttpContext元素的单元测试

it2022-05-05  119

    我们在开发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错误!");}

转载于:https://www.cnblogs.com/wangjq/archive/2010/10/18/1854297.html


最新回复(0)