3

I am unable to unit test one of my functions that contains HttpContext.Current.Request.LogonUserIdentity.Name

The error that I get is because LogonUserIdentity is null.

I added this in my unit test in order to set a value for HttpContext.Current because that was also null:

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

How can I assign a value to LogonUserIdentity so that I can test my function?

BStill
  • 894
  • 1
  • 9
  • 33

5 Answers5

2

This is a sign of much bigger problem to come.

The LogonUserIdentity property exposes the properties and methods of the WindowsIdentity object for the currently connected user to Microsoft Internet Information Services (IIS). The instance of the WindowsIdentity class that is exposed by LogonUserIdentity tracks the IIS request token and provides easy access to this token for the current HTTP request being processed inside of ASP.NET. An instance of the WindowsIdentity class is automatically created so it does not need to be constructed to in order to gain access to its methods and properties.

Source (emphasis mine)

How can I assign a value to LogonUserIdentity so that I can test my function?

You can't. Not in a unit test as IIS is not available.

Avoid tightly coupling your code to untestable code you cannot control like HttpContext and most of System.Web namespace.

Instead, encapsulate them behind abstraction you control and can mock.

Nkosi
  • 235,767
  • 35
  • 427
  • 472
1

I spent a lot of time trying to mock HttpContext or HttpContextBase, then trying to shim with fakes WindowsIdentity class or HttpRequest.LogonUserIdentity property. Nothing works - you don't need completely mocked HttpContext because you want see real responses, not your mock set ups returned. Shims are just not generating for WindowsIdentity class ("due to internal limitations") and for LogonUserIdentity property (no reason given in fakes messages, it's just not there).

The best approach how to get testable HttpContext with request and response is described here: http://jonlanceley.blogspot.com/2015/08/unit-testing-part-2-faking-httpcontext.html

I was able to override LogonUserIdentity property in my fake request wrapper and set there whatever I need.

amarax
  • 508
  • 5
  • 14
1

Not really the best mock, but sometimes you're trapped.

In this solution you must handle locally logged user (johndoe) on controller and/or in your db.

But works.

            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() }
            );
PavelP
  • 119
  • 4
0

You can mock the context as shown here

    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)

I have also a test helper that I wrote, you can find it in Github and try using it, you can modify it to incorporate the above setup https://github.com/danielhunex/TestHelper

Dan Hunex
  • 5,172
  • 2
  • 27
  • 38
  • The controller that I am trying to test is an `ApiController` so I need to use `new HttpControllerContext`. How would I do that? Its giving me errors when trying to use this. – BStill Jul 27 '18 at 22:29
  • Appreciate your approach. I wanna set WindowsIdentity.Token to something. I'm now able to do that using this approach – harinimurugan Apr 17 '19 at 06:55
0

You can mock it using (System.Web.Fakes) like this:

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