如何使用单元测试 测试WEB组件方法中的含有Session、Cookie等HttpContext功能调用的方法?

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

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

具体实现来说:

初始化的时候,使用了 HttpWorkerRequest 抽象类的派生类 SimpleWorkerRequest 来实现初始化。
但是 SimpleWorkerRequest 功能太简单了,不具备Session的功能。

这时候我们就需要用 Mock 技术来构造一个可以满足我们需要的环境的原理:

这个Mock的机制如下:

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

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

具体实现的原理请参看:
http://www.jasonbock.net/JB/Default.aspx?blog=entry.161daabc728842aca6f329d87c81cfcb

但是那里是 .net 1.1 下的做法, .net 2.0 下很多发生变化了,后面整理的代码是 .net 2.0下该如何用的代码。


后面的演示把代码写的很简单,实际应用逻辑可能会很复杂。

比如我们在组件中有这样的一个方法,获得当前登录用户ID:
public static int GetMemberID()
{
    string MemberID = HttpContext.Current.Session["MemberID"].ToString();
    return Convert.ToInt32(MemberID);
}

我们下面就来考虑如何对这个方法进行单元测试。

因为是组件项目,我们无法使用 Visual Studio Team System 的ASP.net单元测试。
我们下面就用模拟的方式来做这个单元测试。
简单来说,就是我们需要构造一个HttpContext对象 ,然后在给其中的Session附值。然后再把它指定到 System.Web.HttpContext.Current 中。

先看一些基础知识:
有关在单元测试中使用HttpContext 的方法,请看下面的链接
Unit testing with HttpContext
http://weblogs.asp.net/jeff/archive/2004/05/31/145111.aspx

模拟的代码简单来说就是:

System.IO.TextWriter tw = new System.IO.StringWriter();
System.Web.HttpWorkerRequest wr = new System.Web.Hosting.SimpleWorkerRequest("/webapp", "c://inetpub//wwwroot//webapp//", "default.aspx", "", tw);
System.Web.HttpContext.Current = new System.Web.HttpContext(wr);

但是需要注意的是,如果我们再简单的增加下面一行,虽然编译没有错误,但是执行不通过。
System.Web.HttpContext.Current.Session["MemberID"] = 1245;
因为SimpleWorkerRequest并没有封装有关Session的功能。

这样我们需要作更多的东西。这就要用到Mock技术.
相关资料请参考:
Adding Session State to a Mock HttpContext Object
http://www.jasonbock.net/JB/Default.aspx?blog=entry.161daabc728842aca6f329d87c81cfcb

但是上面连接是给的.net 1.1下的做法。.net 2.0 下 HttpSessionState函数的构造函数发生了变化。那里的代码很多要发生变化。

.net 2.0 下 HttpSessionState 的构造函数变成了下面方式:
internal HttpSessionState(IHttpSessionState container)
{
      this._container = container;
}

这样我们首先要实现一个 IHttpSessionState 接口的对象。
实现这个接口的范例代码请看:
http://msdn2.microsoft.com/zh-cn/library/system.web.sessionstate.ihttpsessionstate.aspx
其中有一个 MySessionState 就是实现了这个接口。
这个类在我们后面会被用到。

根据上述改变,我们根据 
http://www.jasonbock.net/JB/Default.aspx?blog=entry.161daabc728842aca6f329d87c81cfcb
的知识点,作的 .net 2.0 下的 MockHttpContext 类如下:

    public sealed class MockHttpContext
    {
        private const string ContextKeyAspSession = "AspSession";
        private HttpContext context = null;
        private MockHttpContext() : base() { }
        public MockHttpContext(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;
            }
        }
    }

至于单元测试,则很简单了,如下代码:

[TestMethod()]
public void TestGetMemberIDMethod()
{
    MockHttpContext mock = new MockHttpContext(false);
    System.Web.HttpContext context = mock.Context;
    context.Session["MemberID"] = 1245;

    int id = *****.GetMemberID();

    Assert.AreEqual<int>(id, 1245, "读取用户ID错误!");
}

以上就是使用单元测试 测试组件中的含有Session等HttpContext功能调用的方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值