考虑的一个方法中的一个。净大会:

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.

看看这个 http://haacked.com/archive/2007/06/19/unit-tests-web-code-without-a-web-server-using-httpsimulator.aspx

使用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 会打电话 GetCurrentPrincipalSetAsCurrent 会打电话 SetCurrentPrincipal.

public class MyCustomPrincipal : IPrincipal
{
    public MyCustomPrincipal Current { get; }
    public bool HasCurrent { get; }
    public void SetAsCurrent();
}

这不是真的有关在使用最低采购量为单位的测试你需要什么。

一般来说,我们在工作中有一个分层的结构,上的代码表示层是真的只是为了安排的事情上显示用户界面。这种代码不是复盖有单元的测试。所有其他的逻辑所在业务层,这不必有任何依赖于表示层(即UI具体提及诸如HttpContext)由于UI也可以是一个它应用程序并不一定是一个网络应用程序。

以这种方式可以避免周围的混乱与模拟框架,试图以模拟HttpRequests等虽然通常可能仍然是必要的。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top