我在常规mvc控制器中有一个方法,它检查用户的身份以查看用户应该定向到哪个页面。但是,针对此方法构建单元测试会引发“对象引用未设置”错误,因为当方法作为测试的一部分运行时,User始终为null。
public ActionResult Index()
{
if (User.Identity.IsAuthenticated)
{
if (User.IsInRole("Administrator"))
{
return RedirectToAction("Console");
}
ViewBag.StatusMessage = "You are logged in but do not have sufficient permissions.";
}
else
{
ViewBag.StatusMessage = "Please log in";
}
return View();
}
我尝试了Writing Unit Test for methods that use User.Identity.Name in ASP.NET Web API提供的各种解决方案。这些通常在单元测试的主体内使用如下内容:
var identity = new GenericIdentity("UserName");
Thread.CurrentPrincipal = new GenericPrincipal(identity, null);
var controller = new FooController();
如果Controller是ApiController(即WebApi项目的控制器),这种方法可以正常工作,但它似乎不适用于常规的Web mvc控制器。 User对象保持为null。怎么解决?
答案 0 :(得分:8)
你发布的这个link与WebAPI有关,可以理解的是单元测试ApiController并访问User对象非常容易。
这是与ASP.NET MVC不同的一些,因为您已经看到它并不简单。如果我们走下使用手动/手写模拟的道路,我们可能会发现我们自己嘲笑整个宇宙,反对写一个有价值的测试。
我包含了这两种方法,因此您可以获得这个想法。我也使用了问题中发布的链接中的相同示例。
使用手动手写的模拟
//System Under Test - i.e to test User
public class SutController : Controller
{
public string Get() {
return User.Identity.Name;
}
}
public class TestableControllerContext : ControllerContext {
public TestableHttpContext TestableHttpContext { get; set; }
}
public class TestableHttpContext : HttpContextBase {
public override IPrincipal User { get; set; }
}
[TestMethod]
public void IndexNoneMoq()
{
var identity = new GenericIdentity("tugberk");
var controller = new SutController();
var controllerContext = new TestableControllerContext();
var principal = new GenericPrincipal(identity, null);
var testableHttpContext = new TestableHttpContext
{
User = principal
};
controllerContext.HttpContext = testableHttpContext;
controller.ControllerContext = controllerContext;
Assert.AreEqual(controller.Get(), identity.Name);
}
使用Mocking / Isolation框架,即Moq
[TestMethod]
public void IndexMoq()
{
var identity = new GenericIdentity("tugberk");
var controller = new SutController();
var controllerContext = new Mock<ControllerContext>();
var principal = new Mock<IPrincipal>();
principal.Setup(p => p.IsInRole("Administrator")).Returns(true);
principal.SetupGet(x => x.Identity.Name).Returns("tugberk");
controllerContext.SetupGet(x => x.HttpContext.User).Returns(principal.Object);
controller.ControllerContext = controllerContext.Object;
Assert.AreEqual(controller.Get(), identity.Name);
}
请注意,我认为下一版本的ASP.NET对WebAPI和MVC(AFAIK)使用相同的底层组件,因此这可能是使用User实例的单向测试目标控制器。
答案 1 :(得分:3)
以下是您可以在MVC单元测试控制器中编写的手动模拟。
[TestMethod]
public void IndexManualMoq()
{
.
.
.
var controller = new SutController();
controller.ControllerContext = new ControllerContext
{
HttpContext = new MockHttpContext
{
User = new GenericPrincipal(new GenericIdentity("JDoe"), null)
}
};
.
.
.
}
private class MockHttpContext : HttpContextBase
{
public override IPrincipal User { get; set; }
}