测试自定义AuthorizationAttribute时抛出NullReferenceException

我看了看:

  • 如何进行unit testing以测试检查请求标头的方法?
  • 如何使用moq模拟Controller.User
  • 如何对应用了[Authorize]属性的控制器方法进行unit testing?

我正在尝试测试我编写的自定义AuthorizeAttribute。

我尝试了很多不同的东西来让它发挥作用。 这是我目前的尝试。

[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)] public class ConfigurableAuthorizeAttribute : AuthorizeAttribute { private Logger log = new Logger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); private IRoleHelper roleHelper; public ConfigurableAuthorizeAttribute() { roleHelper = new ADRoleHelper(); } public ConfigurableAuthorizeAttribute(IRoleHelper roleHelper) { this.roleHelper = roleHelper; } protected override bool AuthorizeCore(HttpContextBase httpContext) { if (!httpContext.User.Identity.IsAuthenticated) { return false; } if (this.roleHelper.IsUserInRole(this.Roles, HttpContext.Current.User.Identity.Name)) { return true; } return false; } protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { base.HandleUnauthorizedRequest(filterContext); filterContext.Result = new RedirectResult("~/home/Unauthorized"); } } 
 [Test] public void unauthenticated_user_not_allowed_to_access_resource() { var user = new Mock(); user.Setup(u => u.Identity.IsAuthenticated).Returns(false); var authContext = new Mock(); authContext.Setup(ac => ac.HttpContext.User).Returns(user.Object); var configAtt = new ConfigurableAuthorizeAttribute(); configAtt.OnAuthorization(authContext.Object); authContext.Verify(ac => ac.Result == It.Is(r => r.Url == "")); } 

无论我做什么,我在运行测试时总是得到一个System.NullReferenceException。 它似乎永远不会通过OnAuthorization调用。 堆栈跟踪如下:

结果消息:System.NullReferenceException:未将对象引用设置为对象的实例。 结果StackTrace:位于System.Web.Mvc.AuthorizeAttribute.OnAuthorization(AuthorizationContext filterContext)的System.Web.Mvc.OutputCacheAttribute.GetChildActionFilterFinishCallback(ControllerContext controllerContext)at … ConfigurableAuthorizeAttributeTests.unauthenticated_user_not_allowed_to_access_resource()in … ConfigurableAuthorizeAttributeTests.cs:第29行

有没有人对如何解决这个问题有任何想法?

编辑

我找到了解决方案。 我还需要模拟ControllerDescriptor并确保HttpContextBase.Items返回一个新的Dictionary。

工作代码:

 var context = new Mock(); context.Setup(c => c.Items).Returns(new Dictionary()); context.Setup(c => c.User.Identity.IsAuthenticated).Returns(false); var controller = new Mock(); var actionDescriptor = new Mock(); actionDescriptor.Setup(a => a.ActionName).Returns("Index"); var controllerDescriptor = new Mock(); actionDescriptor.Setup(a => a.ControllerDescriptor).Returns(controllerDescriptor.Object); var controllerContext = new ControllerContext(context.Object, new RouteData(), controller.Object); var filterContext = new AuthorizationContext(controllerContext, actionDescriptor.Object); var att = new ConfigurableAuthorizeAttribute(); att.OnAuthorization(filterContext); Assert.That(filterContext.Result, Is.InstanceOf()); Assert.That(((RedirectResult)filterContext.Result).Url, Is.EqualTo("~/home/Unauthorized")); 

我找到了解决方案。 我还需要模拟ControllerDescriptor并确保HttpContextBase.Items返回一个新的Dictionary。

工作代码:

 var context = new Mock(); context.Setup(c => c.Items).Returns(new Dictionary()); context.Setup(c => c.User.Identity.IsAuthenticated).Returns(false); var controller = new Mock(); var actionDescriptor = new Mock(); actionDescriptor.Setup(a => a.ActionName).Returns("Index"); var controllerDescriptor = new Mock(); actionDescriptor.Setup(a => a.ControllerDescriptor).Returns(controllerDescriptor.Object); var controllerContext = new ControllerContext(context.Object, new RouteData(), controller.Object); var filterContext = new AuthorizationContext(controllerContext, actionDescriptor.Object); var att = new ConfigurableAuthorizeAttribute(); att.OnAuthorization(filterContext); Assert.That(filterContext.Result, Is.InstanceOf()); Assert.That(((RedirectResult)filterContext.Result).Url, Is.EqualTo("~/home/Unauthorized"));