• 单元测试写cookie


    我们在开发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错误!");
    }
  • 相关阅读:
    菜农大叔抢楼
    实验室博客
    VS2008加入QT
    9G关于新唐M0的ISP的要点
    内部函数和外部函数
    51串口通信
    一个三位整数反向后输出
    C++重载函数定义和用法
    博客记录
    C语言练习笔记更新
  • 原文地址:https://www.cnblogs.com/shiningrise/p/5586366.html
Copyright © 2020-2023  润新知