起订量:单元的测试方法依靠HttpContext
-
06-07-2019 - |
题
考虑的一个方法中的一个。净大会:
public static string GetSecurityContextUserName()
{
//extract the username from request
string sUser = HttpContext.Current.User.Identity.Name;
//everything after the domain
sUser = sUser.Substring(sUser.IndexOf("\\") + 1).ToLower();
return sUser;
}
我想这种方法从一个单元试验使用的最低采购量的框架。这会是部分的一个web表单的解决方案。该单元的测试,看起来喜欢这个,但我丢失的最低采购量的代码。
//arrange
string ADAccount = "BUGSBUNNY";
string fullADName = "LOONEYTUNES\BUGSBUNNY";
//act
//need to mock up the HttpContext here somehow -- using Moq.
string foundUserName = MyIdentityBL.GetSecurityContextUserName();
//assert
Assert.AreEqual(foundUserName, ADAccount, true, "Should have been the same User Identity.");
的问题:
- 我如何可以使用最低采购量的安排一个假HttpContext目与一些值像'程序\的配置文件中配置'?
- 我怎么联系的,假的我的电话到我的静态的方法
MyIdentityBL.GetSecurityContextUserName()
? - 你有任何建议,关于如何提高这个代码/架构?
解决方案
Web表单是众所周知的不可测这个确切原因很多代码可以依赖静态的类asp.net 管道。
为了测试,这用最低采购量,需要重构 GetSecurityContextUserName()
方法的使用依赖注射用 HttpContextBase
对象。
HttpContextWrapper
驻留在 System.Web.Abstractions
, ,它船舶。净3.5.这是一个包装 HttpContext
类,并延伸 HttpContextBase
, 和你可以构建一个 HttpContextWrapper
仅仅像这样:
var wrapper = new HttpContextWrapper(HttpContext.Current);
甚至更好的,可以模拟HttpContextBase并设立了您的期望,它使用起订量。其中包括登录用户,等等。
var mockContext = new Mock<HttpContextBase>();
这个地方,你可以打电话 GetSecurityContextUserName(mockContext.Object)
, 和你的应用是多少耦合的静态web表单HttpContext.如果你要做大量的试验,依靠一个被嘲笑的背景下,我强烈建议 看看斯科特Hanselman的MvcMockHelpers类, ,其中有一个版本使用起订量。它方便地处理了很多的设置必要的。尽管名字,你不需要这样做与视-我用它成功地与web表单的应用程序的时候,我可以重构,他们使用 HttpContextBase
.
其他提示
在一般ASP.NET 单元的测试,而不是访问HttpContext.目前,你应该有一个酒店的类型HttpContextBase,其价值是通过依赖注射(例如在回答提供Womp).
但是,对于测试安全有关的职能,我建议使用螺纹。CurrentThread.主要的(而不是HttpContext.电流。用户)。使用螺纹。CurrentThread具有优势的,也正在重复使用外部网上下文中(以及同在网上下文,因为ASP.NET 框架总是集两个数值相同)。
然后测试线。CurrentThread.主要我通常使用范围类集线。CurrentThread测试值,然后重置上的处置:
using (new UserResetScope("LOONEYTUNES\BUGSBUNNY")) {
// Put test here -- CurrentThread.Principal is reset when PrincipalScope is disposed
}
这非常符合标准。净安全组成部分--其中一个组件都有一个已知的接口(IPrincipal)和位置(线。CurrentThread.主要的)--与会的工作与任何代码正确地使用/检查螺纹。CurrentThread.校长。
基范围类将是什么样的以下(必要时进行调整对于像加入角色):
class UserResetScope : IDisposable {
private IPrincipal originalUser;
public UserResetScope(string newUserName) {
originalUser = Thread.CurrentPrincipal;
var newUser = new GenericPrincipal(new GenericIdentity(newUserName), new string[0]);
Thread.CurrentPrincipal = newUser;
}
public IPrincipal OriginalUser { get { return this.originalUser; } }
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing) {
if (disposing) {
Thread.CurrentPrincipal = originalUser;
}
}
}
另一种选择是,而不是使用标准的安全组成部分的位置,写你的应用程序使用注射安全的详细信息,例如增加一个ISecurityContext属性与一个Getcurrent()法或类似的,然后使用这一贯的整个应用程序--但如果你要做这个上下文中的一个网络应用程序,然后你也可能会使用的预先建立的注背景下,HttpContextBase.
使用httpSimulator类,你将能够做到通过HttpContext以处理程序
HttpSimulator sim = new HttpSimulator("/", @"C:\intepub\?")
.SimulateRequest(new Uri("http://localhost:54331/FileHandler.ashx?
ticket=" + myticket + "&fileName=" + path));
FileHandler fh = new FileHandler();
fh.ProcessRequest(HttpContext.Current);
HttpSimulator实现什么,我们需要得到一个HttpContext的实例。所以你并不需要使用最低采购量在这里。
[TestInitialize]
public void TestInit()
{
HttpContext.Current = new HttpContext(new HttpRequest(null, "http://tempuri.org", null), new HttpResponse(null));
}
你也可以最低采购量等下
var controllerContext = new Mock<ControllerContext>();
controllerContext.SetupGet(p => p.HttpContext.Session["User"]).Returns(TestGetUser);
controllerContext.SetupGet(p => p.HttpContext.Request.Url).Returns(new Uri("http://web1.ml.loc"));
如果你使用CLR安全模型(为我们做的),然后你只需要使用一些抽象的功能,以获取和设置目前主要的如果你想要测试,并使用这些时获取或设定的主体。这样做可以让你获得/设定的主体,无论是相关的(通常在 HttpContext
在网络上,并在前线的其他地方的喜欢单元的测试).这看起来是这样的:
public static IPrincipal GetCurrentPrincipal()
{
return HttpContext.Current != null ?
HttpContext.Current.User :
Thread.CurrentThread.Principal;
}
public static void SetCurrentPrincipal(IPrincipal principal)
{
if (HttpContext.Current != null) HttpContext.Current.User = principal'
Thread.CurrentThread.Principal = principal;
}
如果你利用一个自定义的主要后,这些可以相当很好地纳入其接口,例如下面 Current
会打电话 GetCurrentPrincipal
和 SetAsCurrent
会打电话 SetCurrentPrincipal
.
public class MyCustomPrincipal : IPrincipal
{
public MyCustomPrincipal Current { get; }
public bool HasCurrent { get; }
public void SetAsCurrent();
}
这不是真的有关在使用最低采购量为单位的测试你需要什么。
一般来说,我们在工作中有一个分层的结构,上的代码表示层是真的只是为了安排的事情上显示用户界面。这种代码不是复盖有单元的测试。所有其他的逻辑所在业务层,这不必有任何依赖于表示层(即UI具体提及诸如HttpContext)由于UI也可以是一个它应用程序并不一定是一个网络应用程序。
以这种方式可以避免周围的混乱与模拟框架,试图以模拟HttpRequests等虽然通常可能仍然是必要的。