madvora madvora - 2 months ago 17
C# Question

MOQ Unit Test Failing - ASP.NET MVC

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)

);
}
}

Answer

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
Comments