asp.net-mvc-3unit-testingnunitresharperiprincipal

Update: Passing HttpContext and IPrincipal to Controler in ReSharper unit test


I'm attempting to run a couple basic unit tests on an ASP MVC controller, however at one point the controller needs to examine the IPrincipal User object like so:

ViewBag.Level = Security.GetLevel(User);

Once the unit test enters the Create controller method, however, the above line throws a NullReferenceException as the User object is null.

Any ideas on how to set an IPrincipal for a unit test session?

Here's the test as I have it written right now. I attempted to access the User object and simply set it before the test goes into the Create method, however the intellisense isn't picking it up.

    [Test]
    public void a06_CloneFromDatabase()
    {
        using (AgentResources db = new AgentResources())
        {
            var master = (from a in db.AgentTransmission
                          where a.RecordStatus.Equals("C")
                          select a).FirstOrDefault();



            var result = _controlAgtTran.Create(master.ID, null, string.Empty, string.Empty, string.Empty, string.Empty, false) as ViewResult;
            var model = result.Model as AgentTransmission;

            Assert.AreEqual(model.ReferenceType, master.ReferenceType);
        }
    }

EDIT

Following the post mentioned in the comments below I found a method to create a HttpContext session and apply and IPrincipal to that session. This works fine until the unit test moves into the controller where the HttpContext and IPrincipal User objects are all, once again, null.

Since it seems the instance of the controller I'm using has it's HttpContext property as read only (and the IPrincipal User property as well) does anyone know of a way to pass the HttpContext being used in the unit test inside the controller being tested? Also, if this is not possible, what is a usable method for testing RouteValues using ReSharper's unit tests?

    [SetUp]
    public void SetUp()
    {
        _controlAgtTran = new AgentTransmissionController();

        /****Set up Current HTTP Context to pass Security.cs checks*****/

        //Set up the HTTP Request
        var httpRequest = new HttpRequest("", "http://localhost:2574/", "");

        //Set up the HTTP Response
        var httpResponse = new HttpResponse(new StringWriter());

        //Set up the HTTP Context
        var httpContext = new HttpContext(httpRequest, httpResponse);

        var sessionContainer = new HttpSessionStateContainer("NEAROD",
                                                             new SessionStateItemCollection(),
                                                             new HttpStaticObjectsCollection(),
                                                             100,
                                                             true,
                                                             HttpCookieMode.AutoDetect,
                                                             SessionStateMode.InProc,
                                                             false);

        httpContext.Items["AspSession"] =
            typeof (HttpSessionState)
                .GetConstructor(
                    BindingFlags.NonPublic | BindingFlags.Instance,
                    null,
                    CallingConventions.Standard,
                    new[] {typeof (HttpSessionStateContainer)},
                    null)
                .Invoke(new object[] {sessionContainer});

        //Assign the context
        HttpContext.Current = httpContext;
    }

    [Test]
    public void a01_IncompleteRecordGoesToEdit()
    {

        AgentTransmission agtTran = new AgentTransmission();
        agtTran.ReferenceNumber = 95820518787;
        agtTran.ReferenceType = "S";
        agtTran.EffectiveDate = DateTime.Now;
        agtTran.RelationshipEffDate = DateTime.Now;
        agtTran.RecordStatus = "N";
        agtTran.CreatedDate = DateTime.Now;
        agtTran.CreatedOperator = "xTest1";
        agtTran.FirstName = "Unit";
        agtTran.LastName = "Test";
        agtTran.ExtRepType = "EXTREPID";
        agtTran.JIT = true;
        agtTran.SendToDRM = true;
        agtTran.SendToNMF = true;
        agtTran.WelcomeLetter = true;
        agtTran.OverrideRegionInd = false;

        //set IPrincipal 
        string[] roles = {"LCO"};
        IPrincipal principal = new GenericPrincipal(new GenericIdentity("SYMETRA\\NEAROD"), roles);
        HttpContext.Current.User = principal;
        IPrincipal user = HttpContext.Current.User;

        Assert.AreEqual(user, principal); //This passes
        Assert.AreEqual(principal, _controlAgtTran.User); //this fails

        var result = (RedirectToRouteResult)_controlAgtTran.Create(agtTran); //this crashes

        //Tests aren't run
        Assert.IsNotNull(result);
        Assert.AreEqual(3, result.RouteValues.Count);
        Assert.AreEqual("AgentTransmission", result.RouteValues["controller"]);
        Assert.AreEqual("Edit", result.RouteValues["action"]);
    }

Solution

  • Following a similar solution mentioned in this post I added the following to the end of the SetUp() method.

            var controllerCtx = new ControllerContext();
            controllerCtx.HttpContext = new HttpContextWrapper(HttpContext.Current);
            _controlAgtTran.ControllerContext = controllerCtx;
    

    Wrapping the current HttpContext inside an HttpContextBase property (the inappropriately named controllerCtx.HttpContext) the test now has access to the User and HttpContext properties of the controller. These properties were previously read-only when using just the HttpContext.Current session and therefore always null.

    FYI - this is my first time unit testing with these objects so that explanation may be less than 100% correct. Please feel free to comment below and I'll make any necessary changes.