【问题标题】:How do I unit test "HttpContext.Current.Request.LogonUserIdentity.Name"?如何对“HttpContext.Current.Request.LogonUserIdentity.Name”进行单元测试?
【发布时间】:2019-01-05 00:38:02
【问题描述】:

我无法对包含 HttpContext.Current.Request.LogonUserIdentity.Name 的函数之一进行单元测试

我得到的错误是因为LogonUserIdentity 为空。

我在单元测试中添加了这个,以便为 HttpContext.Current 设置一个值,因为它也是 null:

HttpContext.Current = new HttpContext(
            new HttpRequest("", "http://localhost:8609", ""),
            new HttpResponse(new StringWriter())
            );

如何为LogonUserIdentity 赋值以便测试我的功能?

【问题讨论】:

  • 如果你在做单元测试,你可以模拟它
  • @DanHunex 我该怎么做?
  • @DanHunex 我试过这个:stackoverflow.com/a/10126711/7113839
  • @DanHunex 但还是不行
  • 你必须模拟 HttpContextBase。我举个例子

标签: c# unit-testing asp.net-web-api httpcontext


【解决方案1】:

不是最好的模拟,但有时你会被困。

在此解决方案中,您必须在控制器上处理本地登录用户 (johndoe) 和/或 在你的数据库中。

但有效。

            var mockRequest = new HttpRequest("", "http://tempuri.org", "");
            HttpContext.Current = new HttpContext(
                mockRequest,
                new HttpResponse(new StringWriter())
            );

            mockRequest.GetType().InvokeMember(
                "_logonUserIdentity", 
                System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.SetField | System.Reflection.BindingFlags.Instance, 
                System.Type.DefaultBinder,
                mockRequest,
                new object[] { WindowsIdentity.GetCurrent() }
            );

【讨论】:

    【解决方案2】:

    我花了很多时间尝试模拟 HttpContext 或 HttpContextBase,然后尝试使用伪造的 WindowsIdentity 类或 HttpRequest.LogonUserIdentity 属性进行填充。 没有任何效果 - 您不需要完全模拟 HttpContext 因为您想看到真实的响应,而不是返回的模拟设置。 垫片不会为 WindowsIdentity 类(“由于内部限制”)和 LogonUserIdentity 属性生成(假消息中没有给出原因,它只是不存在)。

    这里描述了如何通过请求和响应获取可测试的 HttpContext 的最佳方法: http://jonlanceley.blogspot.com/2015/08/unit-testing-part-2-faking-httpcontext.html

    我能够在我的假请求包装器中覆盖 LogonUserIdentity 属性并在那里设置我需要的任何东西。

    【讨论】:

      【解决方案3】:

      您可以像这样使用 (System.Web.Fakes) 模拟它:

      ShimHttpRequest.AllInstances.LogonUserIdentityGet = (a) => { return WindowsIdentity.GetCurrent(); };

      【讨论】:

      • 既不能填充这个 WindowsIdentity 类,也不能填充 httpRequest 上的这个特定属性
      【解决方案4】:

      您可以模拟这里显示的上下文

          var requestMock = new Mock<HttpRequestBase>();
          var contextMock = new Mock<HttpContextBase>();
          var mockIIdentity = new Mock<IIdentity>();
          mockIIdentity.SetupGet(x => x.Name).Returns("MyName");
          WindowsIdentity windowsIdentity = mockIIdentity.Object as WindowsIdentity;
          requestMock.Setup(x => x.LogonUserIdentity).Returns(windowsIdentity);
          contextMock.Setup(x => x.Request).Returns(requestMock.Object);
      
      
          yourControllerInstance.ControllerContext new  ControllerContext(contextMock.Object, new RouteData(), yourControllerInstance)
      

      我还有一个我写的测试助手,你可以在 Github 中找到它并尝试使用它,你可以修改它以合并上面的设置https://github.com/danielhunex/TestHelper

      【讨论】:

      • 我要测试的控制器是ApiController,所以我需要使用new HttpControllerContext。我该怎么做?尝试使用它时给我错误。
      • 欣赏您的方法。我想将 WindowsIdentity.Token 设置为某些东西。我现在可以使用这种方法做到这一点
      【解决方案5】:

      这预示着更大的问题即将到来。

      LogonUserIdentity 属性为当前连接到 Microsoft Internet 信息服务 (IIS) 的用户公开 WindowsIdentity 对象的属性和方法。 LogonUserIdentity 公开的 WindowsIdentity 类的实例跟踪 IIS 请求令牌,并为在 ASP.NET 内部处理的当前 HTTP 请求提供对该令牌的轻松访问。 WindowsIdentity 类的实例是自动创建的,因此无需构造它即可访问其方法和属性

      Source (强调我的)

      如何为LogonUserIdentity 赋值以便测试我的功能?

      你不能。不在单元测试中,因为 IIS 不可用。

      避免将您的代码与您无法控制的不可测试代码紧密耦合,例如 HttpContext 和大部分 System.Web 命名空间。

      相反,将它们封装在您控制并可以模拟的抽象后面。

      【讨论】:

        猜你喜欢
        • 2012-01-08
        • 2019-11-02
        • 1970-01-01
        • 1970-01-01
        • 2013-09-30
        • 2011-03-16
        • 2013-01-02
        • 2020-04-23
        • 2019-08-10
        相关资源
        最近更新 更多