zoukankan      html  css  js  c++  java
  • 单元测试写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错误!");
    }
  • 相关阅读:
    Android菜鸟的成长笔记(5)——Android系统源代码你下载了吗?
    2014年你不用担心的10件事
    Android菜鸟的成长笔记(4)——你真的理解了吗?
    3. MariaDB设置主从复制
    2. MariaDB激活二进制日志
    如何在CSDN博客自定义栏目中添加“给我写信”
    告别码农,成为真正的程序员
    微信公众平台开发(75)自定义菜单
    大文件分片上传,断点续传,秒传 实现
    大文件上传-大视频上传,T级别的,求解决方案
  • 原文地址:https://www.cnblogs.com/xcj26/p/1918217.html
Copyright © 2011-2022 走看看