Как я могу протестировать атрибут AuthorizeWhereIn с помощью Ninject? - PullRequest
1 голос
/ 21 июля 2011

Я использую пользовательский атрибут авторизации (явно плагиат из другого SO-ответа), но натолкнулся на препятствие, где я не могу найти способ его модульного тестирования. К сожалению, мне нужно выполнить модульное тестирование одновременно с тем, как я вызываю действие моего контроллера, поэтому я пытаюсь найти способ сделать внедрение зависимостей Ninject в модульном тесте.

Атрибут AuthorizeWhereIn:

public class AuthorizeWhereIn : AuthorizeAttribute
{
    /// <summary>
    /// Add the allowed roles to this property.
    /// </summary>
    public new HCIRoles Roles;

    /// <summary>
    /// Checks to see if the user is authenticated and has the
    /// correct role to access a particular view.
    /// </summary>
    /// <param name="httpContext"></param>
    /// <returns></returns>
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        if (httpContext == null)
            throw new ArgumentNullException("httpContext");

        // Make sure the user is authenticated.
        if (!httpContext.User.Identity.IsAuthenticated)
            return false;

        // Get user's current roles
        var roles = System.Web.Security.Roles.GetRolesForUser();
        HCIRoles currentRoles = (HCIRoles)Enum.Parse(typeof(HCIRoles), string.Join(",", roles));

        // Perform a bitwise operation to see if the user's role
        // is in the passed in role values.
        if (Roles != 0 && ((Roles & currentRoles) == 0))
            return false;

        return true;
    }
}

Проблема заключается в вызове System.Web.Security.Roles.GetRolesForUser (), который недоступен в моем модульном тесте и который я хочу каким-либо образом смоделировать. Я могу абстрагировать этот вызов в отдельный интерфейс и использовать Ninject для внедрения его в веб-приложение, но не могу найти способ сделать то же самое в модульном тесте.

Так что, если я изменю атрибут на что-то вроде ниже

public class AuthorizeWhereIn : AuthorizeAttribute
{
     [Inject]
     IRoleService RoleService { get; set; } 

     ...
 }

и мой код модульного теста выглядит следующим образом:

 [TestMethod()]
 public void IndexTest()
 {
      var builder = new TestControllerBuilder();
      var controller = builder.CreateController<UserController>(dataLayer.Object);
  var invoker = new ActionInvoker<UserController>();

      var mockMembershipService = new Mock<IMembershipService>();
      mockMembershipService.Setup(x => x.GetAllUsers(It.IsAny<int>(), It.IsAny<int>(), out       total)).Returns(new MembershipUserCollection());
      controller.MembershipService = mockMembershipService.Object;
      builder.InitializeController(controller);

      invoker.InvokeAction(controller.ControllerContext, x => x.Index());
 }

И тестируемый контроллер:

[AuthorizeWhereIn(Roles = HCIRoles.Admin)]
public class UserController : BaseController
{
    public ActionResult Index()
    {
        return View();
    }
}

У меня вопрос, как я могу внедрить зависимость RolseService в модульный тест, если у меня нет прямого доступа к атрибуту AuthroizeWhereIn?

Я прочитал и перечитал расширение Ninject Filter для MVC3 http://www.planetgeek.ch/2010/11/13/official-ninject-mvc-extension-gets-support-for-mvc3/, но не могу применить его к этому случаю.

Ответы [ 2 ]

4 голосов
/ 21 июля 2011

, учитывая, что я не могу напрямую получить доступ к атрибуту AuthroizeWhereIn

Почему бы не получить к нему доступ напрямую? Это то, что вы пытаетесь проверить в конце концов.

private class TestController : Controller { }

[TestMethod]
public void Test()
{
    // arrange
    var builder = new TestControllerBuilder();
    var controller = new TestController();
    builder.InitializeController(controller);
    controller.ControllerContext = new ControllerContext(builder.HttpContext, new RouteData(), controller);
    var httpContext = builder.HttpContext;
    httpContext.Stub(x => x.Items).Return(new Hashtable());

    var identity = new GenericIdentity("foo");
    var roles = new string[0];
    httpContext.User = new GenericPrincipal(identity, roles);
    var ad = MockRepository.GeneratePartialMock<ActionDescriptor>();
    var context = new AuthorizationContext(controller.ControllerContext, ad);

    var sut = new AuthorizeWhereIn();

    var service = MockRepository.GenerayeStub<IRoleService>();
    sut.RoleService = service;
    // TODO: set expectations on the service

    // act
    sut.OnAuthorization(context);

    // assert
    // TODO: assert on the type of context.Result
    // If it is HttpUnauthorizedResult the authorization has failed
    // (i.e. your custom AuthorizeCore method returned false)
}
0 голосов
/ 22 июля 2011

В итоге коллега нашел умное решение с использованием метода расширения на IPrincipal.Таким образом, нет необходимости вставлять зависимости в атрибут, так как HttpContext можно смоделировать с помощью библиотеки Mvccontrib.

protected override bool AuthorizeCore(HttpContextBase httpContext)
{
    if (httpContext == null)
        throw new ArgumentNullException("httpContext");

    // Make sure the user is authenticated.
    if (!httpContext.User.Identity.IsAuthenticated)
        return false;

    // Get user's current roles
    //var roles = System.Web.Security.Roles.GetRolesForUser();
HCIRoles currentRoles = httpContext.User.GetRoles();

    // Perform a bitwise operation to see if the user's role
    // is in the passed in role values.
    if (Roles != 0 && ((Roles & currentRoles) == 0))
        return false;

    return true;
}

public static HCIRoles GetRoles(this IPrincipal user)
{
HCIRoles roles = 0;

foreach (HCIRoles r in Enum.GetValues(typeof(HCIRoles)))
    {
         if (user.IsInRole(r.ToString()))
    roles |= r;
}

return roles;
}
...