写测试用例的时候经常发现,所写的功能需要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. ContentControl as CC和ContentPresenter as CP的使用

    1.CC为文本控件的父类,它继承为control,所以他是控件, 2.CP继承FrameworkElement,所以他是容器,相当于占位符 3.想让控件中能包含子控件就需要用CP,反之用CC就行.(不 ...

  2. UWP 取消GridView、ListView鼠标选中、悬停效果

    因为经常碰到ListView或者ListBox之类的选中.鼠标悬停样式和自己设置的主题颜色不搭,这时就需要改变这些样式了. 而这里我通过ListView来说明,大致思路其实就是重新定义Item的Tem ...

  3. SpringCloud之Ribbon

    一:Ribbon是什么?  Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起.Ribbon客户端组件提供一系列完善的配置项如连 ...

  4. idea导入myeclipes项目、运行项目

    1. 导入,部署: https://blog.csdn.net/u010570551/article/details/51510447 2. idea导入MyEclipse Web项目时,服务器搭建运 ...

  5. iOS-自定义NavigationItem返回按钮【pop返回按钮】

    在用navigationVC时,返回按钮有时候不想用系统的,这里用继承的方式把按钮替换了,同时也可以实现系统的右滑返回,很简单: 1.创建基类 BasePopViewController 创建一个用于 ...

  6. ORA-01113 & ORA-01110同时出现

    \NOARCHIVED LOG , 没备份 , Redo Log 被覆盖 , 某个datafile不能online 设计知识点:BBED> set block 1BBED> p kcvfh ...

  7. Docker数据管理(五)

    一.什么是数据卷 生成环境中使用docker的过程中,往往需要对数据进行持久化,或者需要多个容器之间进行数据共享,这个就涉及到了容器数据管理 容器中管理数据主要有两种方式: 数据卷:容器内数据之间映射 ...

  8. 前端代码质量保障之代码review

    经验丰富的程序员和一般程序员之间的最大区别,不仅体现在解决问题的能力上, 还体现在日常代码的风格上.掌握一门技术可能需要几月,甚至几周就够了. 好的习惯风格养成却需数年. 团队成员之间需要合作,代码需 ...

  9. 避免resolv.conf设置被覆盖

    resolv.conf文件简介 /etc/resolv文件是系统指定dns服务器地址的配置文件.下面简称resolv.conf 当系统进行域名解析时,会先读取resolv.conf文件中设置的DNS地 ...

  10. Storm的acker确认机制

    Storm的acker消息确认机制... ack/fail消息确认机制(确保一个tuple被完全处理) 在spout中发射tuple的时候需要同时发送messageid,这样才相当于开启了消息确认机制 ...