1

Can someone please help to explain why this is failing? I think I might tracked it down to having something to do with User.Identity.Name. It fails at "Act" and I get a System.NullReferenceException. However another method in the same controller does work.

WORKING TEST

[TestMethod]
public void Home_Index_Returns_ActionResult()
{
    //Arrange
    var mockRepository1 = new Mock<IEditDataRepository>();
    var mockRepository2 = new Mock<IIdentityRepository>();

     mockRepository1
             .Setup(x => x.Edit(It.IsAny<UTCFormViewModel>(), It.IsAny<string>()));
    HomeController controller = new HomeController(mockRepository1.Object, mockRepository2.Object);

    //Act
    ActionResult result = controller.Index();

    //Assert
    Assert.IsInstanceOfType(result, typeof(ActionResult));
}

NOT WORKING TEST (on a different method)

[TestMethod]
public void Edit_Method_Test()
{
    //Arrange
    var mockRepository1 = new Mock<IEditDataRepository>();
    var mockRepository2 = new Mock<IIdentityRepository>();

    mockRepository1
         .Setup(x => x.Edit(It.IsAny<UTCFormViewModel>(), It.IsAny<string>()));

    HomeController controller = new HomeController(mockRepository1.Object, mockRepository2.Object);

    //Act (Fails Here)
    controller.Edit(It.IsAny<UTCFormViewModel>());

    //Assert
    mockRepository1.VerifyAll();
    mockRepository2.VerifyAll();
}

CONTROLLER

namespace UTC.Controllers
{
    [Authorize]
    public class HomeController : Controller       
    {
        private IEditDataRepository _editDataRepository;
        private IIdentityRepository _identityRepository;

        public HomeController(IEditDataRepository editDataRepository, IIdentityRepository identityRepository )
        {
            _editDataRepository = editDataRepository;
            _identityRepository = identityRepository;
        }

        public ActionResult Index()
        {
            return View();
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit([Bind(Include = "Field1, Field2")] UTCFormViewModel model)
        {
            if (ModelState.IsValid)
            {
                string fullWindowsUser = User.Identity.Name;
                string windowsUser = _identityRepository.GetWindowsUser(fullWindowsUser);

                _editDataRepository.Edit(model, windowsUser);
                return new HttpStatusCodeResult(HttpStatusCode.OK);
            }
            else
            {
                throw new HttpException(400, "ModelState Invalid");
            }
        }
    }    
}

REPOSITORY

namespace UTC.Repositories
{
    public class IdentityRepository : IIdentityRepository
    {
        public string GetWindowsUser(string fullWindowsUser)
        {
            //Strip off the domain and lower text
            var windowsUser = fullWindowsUser.ToString().ToLower().Split('\\')[1];

            return windowsUser;
        }
    } 
}

REPOSITORY

namespace UTC.Repositories
{
    public class EditDataRepository : IEditDataRepository
    {
        private UTCEntities db = new UTCEntities();

        public void Edit(UTCFormViewModel model, string windowsUser)
        {
            db.ustp_UTCUpdate(windowsUser, model.Field1, model.Field2)

        );
    }        
}
Nkosi
  • 235,767
  • 35
  • 427
  • 472
madvora
  • 1,717
  • 7
  • 34
  • 49
  • What's the stack trace say? – Rik Oct 04 '16 at 23:06
  • I'm just getting this message `System.NullReferenceException: Object reference not set to an instance of an object.` – madvora Oct 04 '16 at 23:09
  • That's the "message" of the exception. The exception also has a "stacktrace", which will tell you the exact line where it occurred in the controller. Debug the test to inspect it. – Rik Oct 04 '16 at 23:19
  • You would be correct about User.Identity.Name. you need to set a fake user for the controller which is null by default unless otherwise setup in the controller context – Nkosi Oct 04 '16 at 23:20
  • You need to mock the user. Refer the answers [here](http://stackoverflow.com/questions/3027264/mocking-user-identity-in-asp-net-mvc) and [here](http://stackoverflow.com/questions/19006624/how-to-mock-httpcontext-user-identity-name-in-asp-net-mvc-4) –  Oct 04 '16 at 23:20

1 Answers1

1

You are accessing User.Identity.Name but the User property of the controller was not setup in your test method hence it will be null when accessed

you will need to set the controller context with a dummy user account. Here is a helper class you can use to mock the HttpContext needed to get the user principal.

private class MockHttpContext : HttpContextBase {
    private readonly IPrincipal user;

    public MockHttpContext(string username, string[] roles = null) {
        var identity = new GenericIdentity(username);
        var principal = new GenericPrincipal(identity, roles ?? new string[] { });
        user = principal;
    }

    public override IPrincipal User {
        get {
            return user;
        }
        set {
            base.User = value;
        }
    }
}

in your test after initializing the target controller you would need to set the controller context

//...other code removed for brevity

var controller = new HomeController(mockRepository1.Object, mockRepository2.Object);

controller.ControllerContext = new ControllerContext {
    Controller = controller,
    HttpContext = new MockHttpContext("fakeuser@example.com")
};

//...other code removed for brevity
Nkosi
  • 235,767
  • 35
  • 427
  • 472