单元测试写cookie

长平狐 发布于 2013/03/28 14:58
阅读 223
收藏 0

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

原文链接:http://www.cnblogs.com/xcj26/archive/2010/12/27/1918217.html
加载中
返回顶部
顶部