pred pred - 2 months ago 19
C# Question

NullReference durning testing controller with NUnit and Moq

I obtain a NullReference exception in my test. When I comment eventsRepository.AddEvent(eve, User.Identity.GetUserId()); in controller than it goes through.

How Can I fix it ?

Controller's Method

[ValidateAntiForgeryToken]
[HttpPost]
[Authorize]
public ActionResult CreateEvent(Event eve)
{
if (eve.DateOfBegining < DateTime.Now)
{
ModelState.AddModelError("DateOfBegining", "");
}

if (eve.MaxQuantityOfPlayers < eve.MinCount)
{
ModelState.AddModelError("MinCount", "");
}

if (eve.ConflictSides.Count < 2 || eve.ConflictSides.Count > 10)
{
ModelState.AddModelError("ConflictSides", "");
}

if (!ModelState.IsValid)
{
return View("CreateEvent", eve);
}
else
{
eventsRepository.AddEvent(eve, User.Identity.GetUserId());
return RedirectToAction("EventsList");
}
}


AddEvent

void AddEvent(Event ev, string userId);


Test's method

[TestMethod]
public void CreateEvent_AddEvent_returns_EventsList()
{
// arrange
var EventRepo = new Mock<IEventRepository>();
var ParticipantsRepo = new Mock<IParticipants>();

DateTime dt = new DateTime(2200, 1, 23);
Event eve = new Event()
{
ConflictSides = new List<ConflictSide>() {
new ConflictSide{ Name ="niebiescy"},
new ConflictSide{ Name ="czerwoni"},
new ConflictSide{ Name ="fioletowi"},
},
DateOfBegining = dt,
Description = "bardzo dlugi opid na potrzeby testu",
EventCreator= "userId",
EventName = "najlepsza",
FpsLimitInBuildings=300,
FpsLimitOnOpenField=500,
Hicap = new MagazineTyp(){ifAllow = true, ifOnlySemi = false},
MidCap = new MagazineTyp(){ifAllow = true, ifOnlySemi = false},
LowCap = new MagazineTyp(){ifAllow = true, ifOnlySemi = false},
RealCap = new MagazineTyp(){ifAllow = true, ifOnlySemi = false},
MaxQuantityOfPlayers = 50,
MinCount = 10
};

var target = new EventController(EventRepo.Object, ParticipantsRepo.Object);

// act

RedirectToRouteResult result = target.CreateEvent(eve) as RedirectToRouteResult;

// assert

// EventRepo.Verify(a => a.AddEvent(It.IsAny<Event>(), It.IsAny<string>()), Times.Once());

Assert.AreEqual("EventsList", result.RouteValues["action"]);
}

Answer

You are accessing User.Identity.GetUserId() 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 coder

var target = new EventController(EventRepo.Object, ParticipantsRepo.Object);
target.ControllerContext = new ControllerContext {
    Controller = target,
    HttpContext = new MockHttpContext("fakeuser@example.com")
};

//...other coder