0

I have never run Unit testing before and I am just trying to run an example I have found on the net over and over in regards to the view name.

My Test code is:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Admin.Web.API.Controllers;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Web.Mvc;
namespace Admin.Web.API.Controllers.Tests
{
    [TestClass()]
    public class HomeControllerTests
    {
        [TestMethod()]
        public void IndexTest()
        {
            HomeController controller = new HomeController();
            var result = controller.Index() as ViewResult;
            Assert.AreEqual("Index", result.ViewName);
        }
    }
}

The error I am getting is System.NullReferenceException: Object reference not set to an instance of an object. on the Line that sets the view result.

What do I need to do to get this working? Is there anything out there that is more descriptive as to Unit testing examples?

Edit one

Controller Code for Index

public ActionResult Index()
{
    if (this.Session["UserID"] == null)
    {
        return View("Login");
    }
    else
    {
        ViewBag.Title = "Index";
        ViewBag.SiteID = this.Session["SiteID"];
        ViewBag.AssemblyVersion = this.Session["AssemblyVersion"];
        ViewBag.UserFirstName = this.Session["FirstName"];
        GoogleAnalytics _oGoogleAnalytics = new GoogleAnalytics();
        ViewBag.GoogleAnalytics = _oGoogleAnalytics.GetGoogleAnalytics(
            this.Session["GoogleAnalyticsAccountCode"].ToString(),
            Convert.ToBoolean(this.Session["UseGoogleAnalytics"]));
            return View("Index");
    }
}
Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
John Schultz
  • 672
  • 1
  • 10
  • 29
  • @AlexeiLevenkov Seriously, can we stop with this duplicate crap on these kinds of questions? I'm sure the OP knows something is null, but not how to fix the test, which in this case is to provide a ControllerContext to give the controller the needed info. The problem here isn't he doesn't know what a NRE is, its that he doesn't know how to setup the controller properly for unit testing because MVC normally handles that. – Andy Jun 25 '15 at 00:54
  • @AlexeiLevenkov I was giving all that information in my answer when you decided to close this all on your own. The question has all the details needed for someone familiar with the relevant technologies to answer. – Andy Jun 25 '15 at 01:07
  • @Andy OP's problem was completely unrelated to the post according to comment... Don't forget to align question to your future answer when you are done. – Alexei Levenkov Jun 25 '15 at 01:09
  • Could you revise your line about where the error was? I read it as meaning the Assert line since you mention view and result. It might help to comment on the line that failed to be perfectly clear. – Guvante Jun 25 '15 at 01:23
  • @Guvante... pukes on the `controller.index` line – John Schultz Jun 25 '15 at 02:46
  • @AlexeiLevenkov I'm not sure what you mean the problem was unrelated to the post? – Andy Jun 25 '15 at 12:36
  • John, I think my answer will help. – Andy Jun 25 '15 at 13:07
  • @Andy: OP's post - "getting NRE in unit test", actual issue "no idea that server is not running during unit test" (with whole bunch of side issues like not being able to debug code and picking most complicated method for first ever unit test and generally lack of good practices in controller). Your good answer mostly address NRE and not how to write tests for MVC code (really mostly duplicate of http://stackoverflow.com/questions/1228179/mocking-httpcontextbase-with-moq, but ...) – Alexei Levenkov Jun 25 '15 at 14:47
  • @Andy you have not edited title of this post...nor tags - please consider doing so. – Alexei Levenkov Jun 25 '15 at 14:48
  • @AlexeiLevenkov This is a common issue when people start unit testing their MVC code; yes the other question is similar, but that poster already knew he needed to supply the controller with information normally done when running under Asp.Net. Unfortunately for others the reason for the controller missing information is non-obvious and they aren't expecting a NRE, so this question will hopefully serve to connect the dots between the NRE and how to fix it. That said, what exactly do you suggest for edits without losing the path from problem to solution? – Andy Jun 25 '15 at 15:06

2 Answers2

1

You're using the controllers Session property, which will be null because you haven't supplied the controller with the information it needs to create it. This information is normally supplied automatically when running under the Asp.Net pipeline. You can verify this by debugging and stepping into (F11) the Index action method and hovering over Session.

You need to set the ControllerContext property of the controller. Even better would be to use the Authorize attribute on your action method / controller. This is a good post about how to do Forms authentication in MVC.

The simplest way to get your test going though is to use the Controller's User property. You also do this by creating an instance of ControllerContext and setting its HttpContext property, probably by Moq'ing HttpContextBase so that you can return whatever IPrincipal you want.

So this is what you'd need to add after you new up your controller (I'm showing you with the Moq framework, but the VS UnitTest tools might provide its own way to do mocks. Either is fine):

var principalMock = new Mock<IPrincipal>(); // Mock<T> is from the Moq framework
principalMock.Setup(x => x.IsAuthenticated).Returns(true); // Or false, depending on what you're testing

var httpContextMock = new Mock<HttpContextBase>();
httpContextMock.Setup(x => x.User).Returns(principalMock.Object);

var controllerContext = new ControllerContext { HttpContext = contextMock.Object };
conrollerContext.Controller = controller;
controller.ControllerContext = controllerContext;

After you have all that setup, then you can safely call the action method you're testing.

Andy
  • 8,432
  • 6
  • 38
  • 76
0

controller.Index() is not returning a ViewResult and thus result is null.

result.ViewName is then failing as you are dereferencing null.

You need to look at the definition of Index and determine what type of object it is returning. Alternatively you can create a variable for controller.Index() and see what type it has.

EDIT:

Taking a deeper look at Index() it appears that you are relying on some data points that might not be available. The controller is relying on its framework (in this case your test framework) to provide certain pieces, IIRC the Session and ViewBag are two of those pieces.

Guvante
  • 18,775
  • 1
  • 33
  • 64
  • Like I said, I am new to the whole Unit Testing scheme. How do I do that? What do you mean by definition of Index. Are you talking about the controller code for the ActionResult? I'll edit the question and add the Controller code for Index if that helps. – John Schultz Jun 25 '15 at 00:44
  • 2
    @JohnSchultz This issue isn't really related to unit testing at all. Either the method 'Index' on the HomeController class is returning null, or its return type is not ViewResult – Rob Jun 25 '15 at 00:46
  • OK, I commented out everything except the return view and the title and now it works. How am I supposed to do any tests if I cannot determin what page Im on? – John Schultz Jun 25 '15 at 00:50
  • 1
    `Index()` *is* returning a `ViewResult`. I think the more likely explanation (given the new code posted) is that `Session` or `ViewBag` is null. – recursive Jun 25 '15 at 00:50
  • @JohnSchultz: What do you mean by determining what page you're on? When you run a unit test, there is no web server, so things like `Session` and `ViewBag` may not be initialized. – recursive Jun 25 '15 at 00:52
  • The error is happening when he tries to use the controllers Session property, because he hasn't supplied anything to populate it. – Andy Jun 25 '15 at 00:58