写测试用例的时候经常发现,所写的功能需要Http上下文的支持(session,cookie)这类的.

  以下介绍2种应用场景.

用于控制器内Requet获取参数

  控制器内的Requet其实是控制器内的属性.那么在mock的时候把那些上下文附加到Controller里的控制器上下文(ControllerContext )里,request自然就有东西了.

public Controller()

{
/// <summary>
/// 获取或设置控制器上下文。
/// </summary>
///
/// <returns>
/// 控制器上下文。
/// </returns>
public ControllerContext ControllerContext { get; set; } /// <summary>
/// 为当前 HTTP 请求获取 HttpRequestBase 对象。
/// </summary>
///
/// <returns>
/// 请求对象。
/// </returns>
public HttpRequestBase Request
{
get
{
if (this.HttpContext != null)
return this.HttpContext.Request;
return (HttpRequestBase) null;
}
}
}

  

为此,为了单独的Mock这些http上下文中的一些元素,我们需要6个类

Mock类

    //http://stephenwalther.com/archive/2008/07/01/asp-net-mvc-tip-12-faking-the-controller-context
public class FakeControllerContext : ControllerContext
{
//public FakeControllerContext(ControllerBase controller)
// : this(controller, null, null, null, null, null, null)
//{
//} /// <summary>
/// MockCookie
/// </summary>
/// <param name="controller"></param>
/// <param name="cookies"></param>
public FakeControllerContext(ControllerBase controller, HttpCookieCollection cookies)
: this(controller, null, null, null, null, cookies, null)
{
} /// <summary>
/// MockSession
/// </summary>
/// <param name="controller"></param>
/// <param name="sessionItems"></param>
public FakeControllerContext(ControllerBase controller, SessionStateItemCollection sessionItems)
: this(controller, null, null, null, null, null, sessionItems)
{
} /// <summary>
/// MockForm
/// </summary>
/// <param name="controller"></param>
/// <param name="formParams"></param>
public FakeControllerContext(ControllerBase controller, NameValueCollection formParams)
: this(controller, null, null, formParams, null, null, null)
{
} /// <summary>
/// MockForm+QueryString
/// </summary>
/// <param name="controller"></param>
/// <param name="formParams"></param>
/// <param name="queryStringParams"></param>
public FakeControllerContext(ControllerBase controller, NameValueCollection formParams, NameValueCollection queryStringParams)
: this(controller, null, null, formParams, queryStringParams, null, null)
{
} public FakeControllerContext(ControllerBase controller, string userName)
: this(controller, userName, null, null, null, null, null)
{
} public FakeControllerContext(ControllerBase controller, string userName, string[] roles)
: this(controller, userName, roles, null, null, null, null)
{
} /// <summary>
/// Mock Session+Cookie+Form+QuertyString+IIdentity
/// </summary>
/// <param name="controller">控制器名</param>
/// <param name="userName"></param>
/// <param name="roles"></param>
/// <param name="formParams">Form</param>
/// <param name="queryStringParams">QueryString</param>
/// <param name="cookies">Cookie</param>
/// <param name="sessionItems">Session</param>
public FakeControllerContext
(
ControllerBase controller,
string userName,
string[] roles,
NameValueCollection formParams,
NameValueCollection queryStringParams,
HttpCookieCollection cookies,
SessionStateItemCollection sessionItems
)
: base(new FakeHttpContext(
new FakePrincipal(new FakeIdentity(userName), roles),
formParams,
queryStringParams,
cookies, sessionItems), new RouteData(), controller)
{ } /// <summary>
///
/// </summary>
/// <param name="controller"></param>
/// <param name="formParams"></param>
/// <param name="queryStringParams"></param>
/// <param name="cookies"></param>
/// <param name="sessionItems"></param>
/// <param name="userName"></param>
/// <param name="roles"></param>
public FakeControllerContext
(
ControllerBase controller,
NameValueCollection formParams,
NameValueCollection queryStringParams,
HttpCookieCollection cookies,
SessionStateItemCollection sessionItems,
string userName = null,
string[] roles = null
)
: base(new FakeHttpContext(
new FakePrincipal(new FakeIdentity(userName), roles),
formParams,
queryStringParams,
cookies, sessionItems), new RouteData(), controller)
{ }
} public class FakeHttpContext : HttpContextBase
{
private readonly FakePrincipal _principal;
private readonly NameValueCollection _formParams;
private readonly NameValueCollection _queryStringParams;
private readonly HttpCookieCollection _cookies;
private readonly SessionStateItemCollection _sessionItems; public FakeHttpContext(FakePrincipal principal, NameValueCollection formParams, NameValueCollection queryStringParams, HttpCookieCollection cookies, SessionStateItemCollection sessionItems)
{
_principal = principal;
_formParams = formParams;
_queryStringParams = queryStringParams;
_cookies = cookies;
_sessionItems = sessionItems;
} public override HttpRequestBase Request { get { return new FakeHttpRequest(_formParams, _queryStringParams, _cookies); } } public override IPrincipal User { get { return _principal; } set { throw new System.NotImplementedException(); } }
public override HttpSessionStateBase Session { get { return new FakeHttpSessionState(_sessionItems); } }
} public class FakeHttpRequest : HttpRequestBase
{
private readonly NameValueCollection _formParams;
private readonly NameValueCollection _queryStringParams;
private readonly HttpCookieCollection _cookies; public FakeHttpRequest(NameValueCollection formParams, NameValueCollection queryStringParams, HttpCookieCollection cookies)
{
_formParams = formParams;
_queryStringParams = queryStringParams;
_cookies = cookies;
} public override NameValueCollection Form
{
get
{
return _formParams;
}
} public override NameValueCollection QueryString
{
get
{
return _queryStringParams;
}
} public override HttpCookieCollection Cookies
{
get
{
return _cookies;
}
} } public class FakeHttpSessionState : HttpSessionStateBase
{
private readonly SessionStateItemCollection _sessionItems; public FakeHttpSessionState(SessionStateItemCollection sessionItems)
{
_sessionItems = sessionItems;
} public override void Add(string name, object value)
{
_sessionItems[name] = value;
} public override int Count
{
get
{
return _sessionItems.Count;
}
} public override IEnumerator GetEnumerator()
{
return _sessionItems.GetEnumerator();
} public override NameObjectCollectionBase.KeysCollection Keys
{
get
{
return _sessionItems.Keys;
}
} public override object this[string name]
{
get
{
return _sessionItems[name];
}
set
{
_sessionItems[name] = value;
}
} public override object this[int index]
{
get
{
return _sessionItems[index];
}
set
{
_sessionItems[index] = value;
}
} public override void Remove(string name)
{
_sessionItems.Remove(name);
}
} public class FakeIdentity : IIdentity
{
private readonly string _name; public FakeIdentity(string userName) { _name = userName; } public string AuthenticationType { get { throw new System.NotImplementedException(); } } public bool IsAuthenticated { get { return !String.IsNullOrEmpty(_name); } } public string Name { get { return _name; } } } public class FakePrincipal : IPrincipal
{
private readonly IIdentity _identity;
private readonly string[] _roles; public FakePrincipal(IIdentity identity, string[] roles)
{
_identity = identity;
_roles = roles;
} public IIdentity Identity { get { return _identity; } } public bool IsInRole(string role)
{
if (_roles == null)
return false;
return _roles.Contains(role);
}
}

  在原示例里面那个外国佬还mock了其他东西( IPrincipal User).但对于我来说没这方面需求.

  然后我们测试一下.

测试控制器

  public class TestController : Controller
{
#region 请求模拟输出
public ActionResult TestSession()
{
return Content(Session["hehe"].ToString());
} public ActionResult TestCookie()
{
var cookie = Request.Cookies["hehe"];
if (cookie == null)
return new EmptyResult();
return Content(cookie.Values["c1"]);
} #endregion #region 请求测试
public ActionResult TestForm()
{
string fuckyou = Request.Form["fuckyou"];
if (fuckyou == null)
return new EmptyResult();
return Content(fuckyou);
} public ActionResult TestFormAndQueryString()
{
string form = Request.Form["fuckyou"];
string querty = Request.QueryString["fuckyou2"];
return Content(form + "," + querty);
} public ActionResult TestMuilt()
{
var session = Session["hehe"].ToString();
var cookie = Request.Cookies["hehe"].Values["c1"];
string fuckyou = Request.Form["fuckyou"];
string querty = Request.QueryString["fuckyou2"];
return Content(string.Format("{1} {0} {2} {0}{3} {0} {4} {0}", Environment.NewLine, session, cookie, fuckyou, querty));
}
#endregion }

  测试类

    [TestClass]
public class MockRequestTest
{
private readonly IUserCenterService _IUserCenterService;
public MockRequestTest()
{
EngineContext.Initialize(false);
_IUserCenterService = EngineContext.Current.Resolve<IUserCenterService>();
} [Test]
[TestMethod]
public void MockSession()
{
//_IUserCenterService = EngineContext.Current.Resolve<IUserCenterService>();
var controller = new TestController();
var sessionItems = new SessionStateItemCollection();
sessionItems["hehe"] = 23;
controller.ControllerContext = new FakeControllerContext(controller, sessionItems);
var result = controller.TestSession() as ContentResult;
Assert.AreEqual(result.Content, "23");
} [TestMethod]
public void MockCookie()
{
var controller = new TestController();
var mockCookie = new HttpCookie("hehe");
mockCookie["c1"] = "nima1";
mockCookie["c2"] = "nima2";
var requestCookie = new HttpCookieCollection() { { mockCookie } };
controller.ControllerContext = new FakeControllerContext(controller, requestCookie);
var result = controller.TestCookie() as ContentResult;
Console.WriteLine(HttpContext.Current == null);
Assert.AreEqual("nima1", result.Content);
} /// <summary>
/// MockForm
/// </summary>
[TestMethod]
public void MockForm()
{
var controller = new TestController();
NameValueCollection form = new FormCollection()
{
{"fuckyou","1"},
{"fuckyou","2"},
};
controller.ControllerContext = new FakeControllerContext(controller, form);
var result = controller.TestForm() as ContentResult;
Debug.Assert(false, result.Content);
Assert.IsNotNull(result.Content);
} /// <summary>
/// MockForm
/// </summary>
[TestMethod]
public void MockFormAndQueryString()
{
var controller = new TestController();
NameValueCollection form = new FormCollection()
{
{"fuckyou","1"},
{"fuckyou2","2"},
};
controller.ControllerContext = new FakeControllerContext(controller, form, form);
var result = controller.TestFormAndQueryString() as ContentResult;
//Debug.Assert(false, result.Content);
Assert.AreEqual("1,2", result.Content);
} /// <summary>
/// Mock Session+Cookie+Form+QuertyString
/// </summary>
[TestMethod]
public void MockMuilt()
{
var controller = new TestController();
var sessionItems = new SessionStateItemCollection();
sessionItems["hehe"] = 23; var mockCookie = new HttpCookie("hehe");
mockCookie["c1"] = "nima1";
mockCookie["c2"] = "nima2";
var requestCookie = new HttpCookieCollection() { { mockCookie } }; NameValueCollection form = new FormCollection()
{
{"fuckyou","1"},
{"fuckyou2","2"},
}; controller.ControllerContext = new FakeControllerContext(controller, form, form, requestCookie, sessionItems);
var result = controller.TestMuilt() as ContentResult;
Debug.Assert(
false,
result.Content,
string.Format("正确的结果顺序应该是{0};{1};{2};{3};", sessionItems[0], mockCookie["c1"], form["fuckyou"], form["fuckyou2"])
);
}
}

  在上面这个MS测试用例里,我分别测试了

  • Mock session
  • Mock cookie
  • Mock表单
  • Mock 表单+querystring
  • Mock session+cookie+表单+querystring

  都是通过的.

但是这样有个问题.

问题就是:然而这并没有什么卵用.

mock HttpContext.Current

  实际开发的时候.控制器基本打酱油,别的层面需要获取上下文是从HttpContext.Current.Request中获取.如果在刚才的测试用例.控制器输出的是HttpContext.Current.Request.这玩意无疑是null的.因为我们只是把上下文赋值到控制器里的http上下文里面,和HttpContext.Current.Reques是不同的一个概念.

  所以呢,我们需要mock 和HttpContext.Current.Request.

  session的话,比较容易,那就是

SessionStateUtility.AddHttpSessionStateToContext

  cookie的话比较麻烦.HttpRequest.Cookies是一个只读属性,就算用反射赋值也会失败.这里我比较取巧,只用了cookie集合的第一个.有多个的话,可能得把方法改得更恶心一点吧.

代码

  public static class WebExtension
{
/// <summary>
/// 伪造session
/// </summary>
/// <param name="url"></param>
/// <param name="sesion"></param>
/// <param name="queryString"></param>
/// <param name="requesttype"></param>
public static void FakeHttpContext(this string url, SessionStateItemCollection sesion, string queryString = null, string requesttype = null, HttpCookieCollection cookie = null)
{
var stringWriter = new StringWriter();
var httpResponce = new HttpResponse(stringWriter);
HttpRequest request;
if (cookie == null)
{
request = new HttpRequest(string.Empty, url, queryString ?? string.Empty)
{
RequestType = requesttype ?? "GET",
};
}
else
{
request = new HttpRequest(string.Empty, url, queryString ?? string.Empty)
{
RequestType = requesttype ?? "GET",
Cookies = { cookie[0] },
};
}
var httpContext = new HttpContext(request, httpResponce);
if (sesion != null)
{
SessionStateUtility.AddHttpSessionStateToContext(httpContext,
new HttpSessionStateContainer(SessionNameStorage.Suser,
sesion,
new HttpStaticObjectsCollection(),
20000,
true,
HttpCookieMode.AutoDetect,
SessionStateMode.InProc,
false
));
}
if (cookie != null)
{
//无法对只读属性赋值,会导致异常
//Type ret = typeof(HttpRequest);
//PropertyInfo pr = ret.GetProperty("Cookies");
//pr.SetValue(request, cookie, null); //赋值属性 } //var sessionContainer = new HttpSessionStateContainer(
// "id",
// new SessionStateItemCollection(),
// new HttpStaticObjectsCollection(),
// 10,
// true,
// HttpCookieMode.AutoDetect,
// SessionStateMode.InProc,
// false); //httpContext.Items["AspSession"] =
// typeof(HttpSessionState).GetConstructor(
// BindingFlags.NonPublic | BindingFlags.Instance,
// null,
// CallingConventions.Standard,
// new[] { typeof(HttpSessionStateContainer) },
// null).Invoke(new object[] { sessionContainer }); HttpContext.Current = httpContext;
} }

  

相应控制器以及测试用例

        public ActionResult TestHttpCurrent()
{
var a = System.Web.HttpContext.Current;
if (a != null)
{
return Content(a.Request.Cookies.Get("hehe").Value);
}
return Content("");
} [TestMethod]
public void httpCurrent()
{
var controller = new TestController();
var mockCookie = new HttpCookie("hehe");
mockCookie["c1"] = "nima1";
mockCookie["c2"] = "nima2";
var requestCookie = new HttpCookieCollection() { { mockCookie } };
string.Format("{0}/test/TestHttpCurrent", TestHelper.WebRootUrl).FakeHttpContext(sesion: null, cookie: requestCookie);
var result = controller.TestHttpCurrent() as ContentResult;
Console.WriteLine(result.Content); }

  session就不测了,我平时测试的时候试了无数次都是有的.

备注:

mock cookie那里,如果有更好的实现方式,请告诉我.

标题是故意为之的,代表了我对ASB.NET 的嘲讽.

参考链接:

ASP.NET MVC Tip #12 – Faking the Controller Context


ASP.NET MVC, HttpContext.Current is null while mocking a request

Mock session,cookie,querystring in ASB.NET MVC的更多相关文章

  1. Asp.net MVC使用Model Binding解除Session, Cookie等依赖

    上篇文章"Asp.net MVC使用Filter解除Session, Cookie等依赖"介绍了如何使用Filter来解除对于Session, Cookie的依赖.其实这个也可以通 ...

  2. Asp.net MVC使用Filter解除Session, Cookie等依赖

    本文,介绍了Filter在MVC请求的生命周期中的作用和角色,以及Filter的一些常用应用场景. 同时针对MVC中的对于Session,Cookie等的依赖,如何使用Filter解依赖. 如果大家有 ...

  3. [转]Asp.net MVC使用Filter解除Session, Cookie等依赖

    本文转自:http://www.cnblogs.com/JustRun1983/p/3279139.html 本文,介绍了Filter在MVC请求的生命周期中的作用和角色,以及Filter的一些常用应 ...

  4. web也是区分前端与后端的,session\cookie辨析

    <1>Ajax交互方式 Ext.Ajax.request( { //被用来向服务器发起请求默认的url url : "", //请求时发送后台的参数,既可以是Json对 ...

  5. Asp.net 服务器Application,Session,Cookie,ViewState和Cache区别

    2.8 Context 的使用Context 对象包含与当前页面相关的信息,提供对整个上下文的访问,包括请求.响应.以及上文中的Session 和Application 等信息.可以使用此对象在网页之 ...

  6. session & cookie(li)

    Session & Cookie 一.定义 Session,用户在浏览某个网站时,从进入网站到浏览器关闭所经过的这段时间,也就是用户浏览这个网站所花费的时间.Cookie,由服务器端生成,发送 ...

  7. 浅析session&cookie

    session&cookie没有出现的黑暗时代 大家都知道,HTTP协议是一种无状态的协议,本次请求下一次请求没有任何的关联,所有没有办法直接用http协议来记住用户的信息,试想一向,每一次点 ...

  8. http之Session&Cookie

    百度了一波session与Cookie,我发现这东西远比我想象中更复杂(可能是因为我不明白底层的运行原理).网上也是一堆的关于Session与Cookie区别/联系的文章,然而,我看完了还是一脸懵逼的 ...

  9. [转载]JavaEE学习篇之——Session&&Cookie

    原文链接: http://blog.csdn.net/jiangwei0910410003/article/details/23337043 今天继续来看看JavaWeb的相关知识,这篇文章主要来讲一 ...

随机推荐

  1. .NET 证书加密 存储保存 IIS授权

    最近接到一个任务,加密DotNet项目的配置文件.配置文件里需要加密的地方一共有两块,一个是数据库连接字符串,一个是自定义的所有AppSettings. 一开始接到这个任务我是拒绝的,因为压根不知道怎 ...

  2. C# Winform模仿百度日历

    想写博客不知道从何处开始,就从回忆开始吧. 第一个就从自定义日历控件开始 产生背景: 大概2015年时候有个项目要用到日历,用默认日历展示给用户看,用户毫不客气都说界面太丑,最好做成像百度日历那样方便 ...

  3. JVM活学活用——类加载机制

    类的实例化过程 有父类的情况 1. 加载父类静态    1.1 为静态属性分配存储空间并赋初始值     1.2 执行静态初始化块和静态初始化语句(从上至下) 2. 加载子类静态    2.1 为静态 ...

  4. 【PHP】当mysql遇上PHP

    博客提纲 利用PHP连接mySQL数据库 两套接口:面向对象和面向过程 实现写改删查(CUBD)实例 通过prepare语句处理相同类型的不同SQL语句 通过bind_param()绑定参数,及相关注 ...

  5. 【javascript】原生js更改css样式的两种方式

    下面我给大家介绍的是原生js更改CSS样式的两种方式: 1通过在javascript代码中的node.style.cssText="css表达式1:css表达式2:css表达式3  &quo ...

  6. C# Winform下一个热插拔的MIS/MRP/ERP框架(简介)

    Programmer普弱哥们都喜欢玩自己的框架,我也不例外. 理想中,这个框架要易于理解.易于扩展.易于维护:最重要的,易于CODING. 系统是1主体框架+N模组的多个EXE/DLL组成的,在主体框 ...

  7. cad.net的undo返回操作

    这是提供给许多从lisp转移到c#的开发人员的一个函数,这个函数利用后绑代码实现undo返回操作. 本代码由edata提供: edata博客 /// <summary> /// 命令动作编 ...

  8. 2018 Multi-University Training Contest 6

    A.oval-and-rectangle 题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6362 题意:在长半轴为a,短半轴为b的椭圆内部,以y=c( ...

  9. D13——C语言基础学PYTHON

    C语言基础学习PYTHON——基础学习D13 20180918内容纲要: 堡垒机运维开发 1.堡垒机的介绍 2.堡垒机的架构 3.小结 4.堡垒机的功能实现需求 1 堡垒机的介绍 百度百科 随着信息安 ...

  10. django admin编辑被外键关联的主表时支持显示字表记录

    假设有模型 class A(models.Model): name = models.CharField() class B(models.Model): name = models.CharFiel ...