我正试图在ASP MVC控制器上运行几个基本的单元测试,但在某一点上,控制器需要检查IPrincipal
User
对象,如下所示:
ViewBag.Level = Security.GetLevel(User);
然而,一旦单元测试进入Create
控制器方法,由于User
对象是null
,所以上面的行抛出一个NullReferenceException
。
关于如何为单元测试会话设置IPrincipal
,有什么想法吗?
这是我现在写的测试。我试图访问User
对象,并在测试进入Create
方法之前简单地对其进行设置,但intellisense没有接收到它。
[Test]
public void a06_CloneFromDatabase()
{
using (AgentResources db = new AgentResources())
{
var master = (from a in db.AgentTransmission
where a.RecordStatus.Equals("C")
select a).FirstOrDefault();
var result = _controlAgtTran.Create(master.ID, null, string.Empty, string.Empty, string.Empty, string.Empty, false) as ViewResult;
var model = result.Model as AgentTransmission;
Assert.AreEqual(model.ReferenceType, master.ReferenceType);
}
}
编辑
根据下面评论中提到的帖子,我找到了一种创建HttpContext
会话并将IPrincipal
应用于该会话的方法。在单元测试进入HttpContext
和IPrincipal
User
对象都为空的控制器之前,这种情况一直很好。
由于我使用的控制器的实例的HttpContext
属性似乎是只读的(还有IPrincipal
User
属性),有人知道在被测试的控制器内部通过单元测试中使用的HttpContext
的方法吗?此外,如果这不可能,使用ReSharper的单元测试测试RouteValues
的可用方法是什么?
[SetUp]
public void SetUp()
{
_controlAgtTran = new AgentTransmissionController();
/****Set up Current HTTP Context to pass Security.cs checks*****/
//Set up the HTTP Request
var httpRequest = new HttpRequest("", "http://localhost:2574/", "");
//Set up the HTTP Response
var httpResponse = new HttpResponse(new StringWriter());
//Set up the HTTP Context
var httpContext = new HttpContext(httpRequest, httpResponse);
var sessionContainer = new HttpSessionStateContainer("NEAROD",
new SessionStateItemCollection(),
new HttpStaticObjectsCollection(),
100,
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});
//Assign the context
HttpContext.Current = httpContext;
}
[Test]
public void a01_IncompleteRecordGoesToEdit()
{
AgentTransmission agtTran = new AgentTransmission();
agtTran.ReferenceNumber = 95820518787;
agtTran.ReferenceType = "S";
agtTran.EffectiveDate = DateTime.Now;
agtTran.RelationshipEffDate = DateTime.Now;
agtTran.RecordStatus = "N";
agtTran.CreatedDate = DateTime.Now;
agtTran.CreatedOperator = "xTest1";
agtTran.FirstName = "Unit";
agtTran.LastName = "Test";
agtTran.ExtRepType = "EXTREPID";
agtTran.JIT = true;
agtTran.SendToDRM = true;
agtTran.SendToNMF = true;
agtTran.WelcomeLetter = true;
agtTran.OverrideRegionInd = false;
//set IPrincipal
string[] roles = {"LCO"};
IPrincipal principal = new GenericPrincipal(new GenericIdentity("SYMETRA\NEAROD"), roles);
HttpContext.Current.User = principal;
IPrincipal user = HttpContext.Current.User;
Assert.AreEqual(user, principal); //This passes
Assert.AreEqual(principal, _controlAgtTran.User); //this fails
var result = (RedirectToRouteResult)_controlAgtTran.Create(agtTran); //this crashes
//Tests aren't run
Assert.IsNotNull(result);
Assert.AreEqual(3, result.RouteValues.Count);
Assert.AreEqual("AgentTransmission", result.RouteValues["controller"]);
Assert.AreEqual("Edit", result.RouteValues["action"]);
}
根据本文中提到的类似解决方案,我在SetUp()
方法的末尾添加了以下内容。
var controllerCtx = new ControllerContext();
controllerCtx.HttpContext = new HttpContextWrapper(HttpContext.Current);
_controlAgtTran.ControllerContext = controllerCtx;
将当前HttpContext
封装在HttpContextBase
属性(名称不恰当的controllerCtx.HttpContext
)中,测试现在可以访问控制器的User
和HttpContext
属性。当仅使用HttpContext.Current
会话时,这些属性以前是只读的,因此始终为null。
仅供参考——这是我第一次用这些对象进行单元测试,因此解释可能不到100%正确。请随时在下面发表评论,我会做出任何必要的更改。