Reputation: 59
I am getting the following error when running unit test: NullReferenceException was unhandled by usercode. Object reference was not set to an instance of an object.
Not sure where I am going wrong. Please advice.
My SessionManager.cs class
public static int customerID
{
get
{
if (HttpContext.Current.Session != null &&
HttpContext.Current.Session[_customerID] != null)
{
return Convert.ToInt32(HttpContext.Current.Session[_customerID]);
}
else
{
throw new Ramsell.ExceptionManagement.RamsellException();
}
}
set
{
if (HttpContext.Current.Session == null) return;
HttpContext.Current.Session[_customerID] = value;
}
}
ParticipantController
public ActionResult Index()
{
int custId = Convert.ToInt32(SessionManager.customerID);
//code logic about participant lists
return View();
}
Test method :
[TestMethod]
public void IndexTest()
{
ParticipantController pCTarget = new ParticipantController();
const int page = 1;
const string sortBy = "FirstName";
const bool ascending = true;
const string partname = "";
const int success = -1;
const string id = "";
var expected = typeof(ParticipantListViewModel);
ViewResult result = pCTarget.Index(page, sortBy, ascending, partname, success, id) as ViewResult;
Assert.AreEqual(expected, result.Model.GetType());
}
//This is my mock class
public Mock<RequestContext> RoutingRequestContext { get; private set; }
public Mock<HttpContextBase> Http { get; private set; }
public Mock<HttpServerUtilityBase> Server { get; private set; }
public Mock<HttpResponseBase> Response { get; private set; }
public Mock<HttpRequestBase> Request { get; private set; }
public Mock<HttpSessionStateBase> Session { get; private set; }
public Mock<ActionExecutingContext> ActionExecuting { get; private set; }
public HttpCookieCollection Cookies { get; private set; }
public MockContext()
{
this.RoutingRequestContext = new Mock<RequestContext>(MockBehavior.Loose);
this.ActionExecuting = new Mock<ActionExecutingContext>(MockBehavior.Loose);
this.Http = new Mock<HttpContextBase>(MockBehavior.Loose);
this.Server = new Mock<HttpServerUtilityBase>(MockBehavior.Loose);
this.Response = new Mock<HttpResponseBase>(MockBehavior.Loose);
this.Request = new Mock<HttpRequestBase>(MockBehavior.Loose);
this.Session = new Mock<HttpSessionStateBase>(MockBehavior.Loose);
this.Cookies = new HttpCookieCollection();
this.RoutingRequestContext.SetupGet(c => c.HttpContext).Returns(this.Http.Object);
this.ActionExecuting.SetupGet(c => c.HttpContext).Returns(this.Http.Object);
this.Http.SetupGet(c => c.Request).Returns(this.Request.Object);
this.Http.SetupGet(c => c.Response).Returns(this.Response.Object);
this.Http.SetupGet(c => c.Server).Returns(this.Server.Object);
this.Http.SetupGet(c => c.Session).Returns(this.Session.Object);
this.Request.Setup(c => c.Cookies).Returns(Cookies);
var sessionContainer = new HttpSessionStateContainer("userID", new SessionStateItemCollection(),
new HttpStaticObjectsCollection(), 1, true,
HttpCookieMode.AutoDetect,
SessionStateMode.InProc, false);
this.Session.Setup(c => c.Add("AspSession", typeof(HttpSessionState).GetConstructor(
BindingFlags.NonPublic | BindingFlags.Instance,
null, CallingConventions.Standard,
new[] { typeof(HttpSessionStateContainer) },
null)
.Invoke(new object[] { sessionContainer })));
}
Upvotes: 1
Views: 4213
Reputation: 236328
When you are writing unit tests for controller, you should test it in isolation - i.e. controller's dependencies should be mocked. So, make sure that your controller depends on abstraction rather than concrete SessionManager
implementation (make your class non-static and extract ISessionManager
interface from your manager class):
public interface ISessionManager
{
int CustomerID { get; set; }
}
public class HttpSessionManager : ISessionManager
{
// your current implementation goes here
}
Then mock this abstraction and inject it to controller (sample with Moq):
[TestMethod]
public void IndexTest()
{
var sessionManager = new Mock<ISessionManager>(); // Mock dependency
sessionManager.Setup(m => m.CustomerID).Returns(42);
const int page = 1;
const string sortBy = "FirstName";
const bool ascending = true;
const string partname = "";
const int success = -1;
const string id = "";
var expectedModelType = typeof(ParticipantListViewModel);
ParticipantController pCTarget =
new ParticipantController(sessionManager.Object); // Inject dependency
var view = pCTarget.Index(page, sortBy, ascending, partname, success, id)
as ViewResult;
sessionManager.VerifyGet(m => m.CustomerID); // Verify dependency was called
Assert.AreEqual(expectedModelType, view.Model.GetType());
}
And here is controller code:
public class ParticipantController : Controller
{
private readonly ISessionManager _sessionManager;
public ParticipantController(ISessionManager sessionManager)
{
_sessionManager = sessionManager;
}
public ActionResult Index()
{
int custId = _sessionManager.CustomerID;
//code logic about participant lists
return View();
}
}
Note that goal of unit-testing is to make you sure that every small part of code is working as expected. If you will depend on other units in test, then test can fail for two reasons - your unit under test behaves not as expected, or there is something wrong with dependency You already hit that case - controller test failed because session manager throws exception. Tests says that controller behaves not as expected. Is it true? No - it's session manager behaves not as expected.
Upvotes: 2