2

I've just started programming in C# Webforms (previous experience in VB Webforms) and I am producing a web app that will be a small part of a bigger project.

I have created 3 separate projects, one for the webforms, one for the class library and one for the tests.

I have added all the projects into one solution and added appropriate references, Both the Webforms and Tests projects reference the class library.

I have a class in the class library that finds the username of the logged in user:

public class LoggedInUser
{
    public string UserName 
    {
        get { return HttpContext.Current.User.Identity.Name; } 
    }

}

In the page load event of one of my pages, I use this class to set the text property of a literal to display the name on the screen.

    protected void Page_Load(object sender, EventArgs e)
    {
        LoggedInUser CurrentUser = new LoggedInUser();
        LitUser.Text = string.Format(" {0}", CurrentUser.UserName);
    }

This works fine.

To be complete I thought I would write a unit test to make sure the logged in username is what I expected.

    [TestMethod]
    public void Test_Logged_In_User_Name()
    {
        LoggedInUser actualUser = new LoggedInUser();
        string expectedUserName = "myUserName";
        string actualUserName = actualUser.UserName;
        Assert.AreEqual(expectedUserName, actualUserName);
    }

When I run the test it throws the following exception:

System.NullReferenceException: Object reference not set to an instance of an object

on this line:

get { return HttpContext.Current.User.Identity.Name; }

Any thoughts would as always be greatly appreciated.

Simon
  • 1,293
  • 5
  • 21
  • 39

2 Answers2

1

You'll need to create a wrapper class for HttpContext that abstracts the functionality you need. The reason for this is that HttpContext only exists for web requests and as you are running your unit tests from an application HttpContext will not exist.

Additionally any 3rd party dependency should have a wrapper created for it to assist with testing.

It's worth noting, you also shouldn't need this test at all. In this instance you are testing a 3rd parties code, something you are relying on to be accurate. The purpose of unit tests is to test your own code/logic and if you wrote tests for every 3rd party method you'd never get a product released :).

As for creating a wrapper class, they are not dissimilar from ordinary classes. You'd need to create an interface for the HttpContext class and then create a wrapper something like the below:

public class HttpContextWrapper
{
    private readonly IHttpContext _httpContext;

    public HttpContextWrapper()
    {
        _httpContext = HttpContext.Current;
    }

    public HttpContextWrapper(IHttpContext injectedContext)
    {
        _httpContext = injectedContext;
    }

    public string GetName()
    {
        _httpContext.Current.User.Identity.Name;
    }
}

You could then inject a fake implimentation of HttpContext to get your desired results.

Lee
  • 366
  • 2
  • 12
  • Thanks for that, as I said before I am beginner with this...how do i go about doing what you say? – Simon Nov 18 '15 at 11:40
0

Actually, you don't necessarily need to wrap and mock the HttpContext. In your test setup, you can do something similar to the following:

var sb = new StringBuilder();
TextWriter writer = new StringWriter(sb);
HttpContext.Current = new HttpContext(
     new HttpRequest("path", "http://dummy", ""), 
     new HttpResponse(writer)
)
{
    User = new WindowsPrincipal(WindowsIdentity.GetCurrent()) 
};

In this example, I assign a windows principal with the identity of the current user, but in your scenario you may want to assign a specifically crafted principal, e.g. a ClaimsPrincipal or a fake implementation (or a mock).

jeroenh
  • 26,362
  • 10
  • 73
  • 104