我正在尝试为相当基本的控制器操作编写一些单元测试,其中我设置了Session [" User"]。当我运行测试时,它在此时失败并带有空引用异常。不完全确定如何绕过这个。
控制器:
public ActionResult Index(int id)
{
Session["User"] = Id;
if (Id != 0)
{
return RedirectToAction("Home", "Home", new { Id});
}
return RedirectToAction("Register", "Home", new { Id});
}
测试:
[TestMethod]
public void NewUser_ShouldGoToRegister()
{
var controller = new HomeController();
HttpContext.Current = FakeHttpContext();
HttpContext.Current.Session.Add("User", "0");
var result = controller.Index(0) as ViewResult;
Assert.AreEqual("Register", result.ViewName);
}
public HttpContext FakeHttpContext()
{
var httpRequest = new HttpRequest("", "http://localhost/", "");
var httpResponce = new HttpResponse(new StringWriter());
var httpContext = new HttpContext(httpRequest, httpResponce);
var sessionContainer =
new HttpSessionStateContainer("id",
new SessionStateItemCollection(),
new HttpStaticObjectsCollection(),
10,
true,
HttpCookieMode.AutoDetect,
SessionStateMode.InProc,
false);
httpContext.Items["AspSession"] =
typeof(HttpSessionState)
.GetConstructor(
BindingFlags.NonPublic | BindingFlags.Instance,
null,
CallingConventions.Standard,
new[] { typeof(HttpSessionStateContainer) },
null)
.Invoke(new object[] { sessionContainer });
HttpContext.Current = httpContext;
}
答案 0 :(得分:1)
您可以使用某些模拟工具(如MOQ
进行模拟)来创建虚假HttpContext
,您可以尝试使用以下代码。
[TestMethod]
public void NewUser_ShouldGoToRegister()
{
var controller = new HomeController();
HttpContext.Current = FakeHttpContext();
HttpContext.Current.Session.Add("User", 1);
var result = controller.Index(0) as ViewResult;
Assert.AreEqual("Register", result.ViewName);
}
您的FakeHttpContext
方法应如下所示。
//Creating a Fake HTTP Context
// This is used for testing methods using Session Variables.
private HttpContext FakeHttpContext()
{
var httpRequest = new HttpRequest("", "http://somethig.com/", "");
var stringWriter = new StringWriter();
var httpResponce = new HttpResponse(stringWriter);
var httpContext = new HttpContext(httpRequest, httpResponce);
var sessionContainer =
new HttpSessionStateContainer("id", new SessionStateItemCollection(),
new HttpStaticObjectsCollection()
, 10,
true,
HttpCookieMode.AutoDetect,
SessionStateMode.InProc, false);
httpContext.Items["AspSession"] =
typeof(HttpSessionState).GetConstructor(
BindingFlags.NonPublic | BindingFlags.Instance,
null, CallingConventions.Standard,
new[] { typeof(HttpSessionStateContainer) },
null)
.Invoke(new object[] { sessionContainer });
return httpContext;
}
答案 1 :(得分:0)
如果你有这方面的困难,这个想法可能会帮助你过度思考它。有时,创建Session
的另一层访问权限是个好主意。
简化的方法是永远不要直接访问" Session",而是将其包含在这样的方法中:
protected virtual string ReadFromSession(string key)
{
return Session[key];
}
protected virtual void StoreInSession(string key, string value)
{
Session[key] = value;
}
在Controller中的任何地方,您只需使用这些方法,而不是直接访问Session
。很容易。
现在的诀窍是使用单元测试,您可以覆盖您测试的控制器:
public class MyControllerForTesting : MyController
{
private readonly IDictionary session;
public MyControllerForTesting(IDictionary session) : base()
{
this.session = session;
}
protected override string ReadFromSession(string key)
{
return this.session[key];
}
protected override void StoreInSession(string key, string value)
{
this.session[key] = value;
}
}
现在这可能不会立即起作用,因为我没有真正测试它,但你得到了想法。您的单元测试工作,如果值设置正确等,您甚至可以检查字典。