Yordanka Toteva
Yordanka Toteva

Reputation: 65

ASP.NET MVC unit testing method that returns session

I am doing unit tests using NUnit and Moq. I tried this example that checks whether a session object called Role exists. If not, it creates it, and returns an object of type Role.

protected Role GetRole()
    {
        if (Session["Role"] == null)
        {
            Session["Role"] = new Role();
        }

        return Session["Role"] as Role;
    }

Then I use it in the Index action:

public ActionResult Index()
    {
        var roles = GetRole();
        roles.RoleName = "Test";
        return View();
    }

And this is my test:

[Test]
    public void TestMethod1()
    {
        var contextMock = new Mock<ControllerContext>();
        var mockHttpContext = new Mock<HttpContextBase>();
        var session = new Mock<HttpSessionStateBase>();

        mockHttpContext.Setup(ctx => ctx.Session).Returns(session.Object);
        contextMock.Setup(ctx => ctx.HttpContext).Returns(mockHttpContext.Object);

        contextMock.Setup(p => p.HttpContext.Session["Role"]).Returns(new Role
                                                                      {
                                                                          RoleId = 1,
                                                                          RoleName = "Test"
                                                                      });
        var homeController = new HomeController();
        homeController.ControllerContext = contextMock.Object;
        var indexView = homeController.Index();
        Assert.IsNotNull(indexView);
    }

It runs successfully. But when I check the code coverage, it gives me that the Session["Role"] = new Role(); part is not covered by the test code. So I made another test. There I don't setup the session variable Role:

[Test]
    public void TestMethod2()
    {
        var contextMock = new Mock<ControllerContext>();
        var mockHttpContext = new Mock<HttpContextBase>();
        var session = new Mock<HttpSessionStateBase>();

        mockHttpContext.Setup(ctx => ctx.Session).Returns(session.Object);
        contextMock.Setup(ctx => ctx.HttpContext).Returns(mockHttpContext.Object);
        var homeController = new HomeController();
        homeController.ControllerContext = contextMock.Object;
        var indexView = homeController.Index();

        Assert.IsNotNull(indexView);
        Assert.IsNull(homeController.ControllerContext.HttpContext.Session["Role"]);
    }

But it fails - it gives System.NullReferenceException : Object reference not set to an instance of an object because of the roles.RoleName = "Test"; row. How to make it run? Thank you in advance!

Upvotes: 1

Views: 1081

Answers (1)

DavidG
DavidG

Reputation: 118937

The problem you have is that in the second test Session["Role"] will never return anything as it's a mocked object set up to always return null. One possible workaround is to change your GetRole function to this and adjust your tests:

protected Role GetRole()
{
    var role = Session["Role"] as Role;

    if (role == null)
    {
        role = new Role();
        Session["Role"] = role;
    }

    return role;
}

Upvotes: 2

Related Questions