Модульное тестирование бритвенных страниц, которые наследуются от BasePageModel - PullRequest
1 голос
/ 18 июня 2019

У меня есть приложение Razor Pages, в котором несколько служб используются всеми страницами сайта, и я добавил эти службы в BasePageModel, который я наследую на каждой странице Razor.Мой BasePageModel выглядит примерно так:

public abstract class BasePageModel : PageModel
{
    private IUserClaimsService _userClaims;
    private IAuthorizationService _authService;

    protected virtual IUserClaimsService UserClaimsService => _userClaims ?? (_userClaims = HttpContext.RequestServices.GetService<IUserClaimsService>());
    protected virtual IAuthorizationService AuthService => _authService ?? (_authService = HttpContext.RequestServices.GetService<IAuthorizationService>()); 
}

Сама страница Razor будет выглядеть примерно так:

public class IndexModel : BasePageModel
{
    public async Task<ActionResult> OnGet()
    {
        var HasAccess = (await AuthService.AuthorizeAsync(User, "PermissionName")).Succeeded;
        if (!HasAccess)
        {
            return new ForbidResult();
        }
        return Page();
    }
}

Я создаю модульные тесты для проверки авторизации на моих страницах Razor.Моя авторизация имеет политики, которые зависят от утверждений пользователей.Я хотел бы посмеяться над утверждениями пользователей и проверить, успешно ли проходит авторизация или нет, в зависимости от страницы.Однако я не могу добраться до UserClaimsService, чтобы высмеять его из моего теста.Я создаю экземпляр pageModel, но не могу получить ни одно из значений BasePageModel (например, UserClaimsService).Есть идеи, как мне это сделать?

1 Ответ

2 голосов
/ 18 июня 2019

Следует избегать использования шаблона поиска служб, используемого через службы запросов.Следуйте Явному принципу зависимости через внедрение конструктора.

public abstract class BasePageModel : PageModel {
    protected readonly IAuthorizationService authService;

    protected BasePageModel(IAuthorizationService authService) {
        this.authService = authService;
    }

    protected async Task<bool> HasAccess(string permissionName) {
        return (await authService.AuthorizeAsync(User, permissionName)).Succeeded;
    }
}

Сама страница Razor стала бы

public class IndexModel : BasePageModel {
    public IndexModel(IAuthorizationService authService) : base (authService) {
        //...
    }

    public async Task<ActionResult> OnGet() {
        if (!HasAccess("PermissionName")) {
            return new ForbidResult();
        }
        return Page();
    }
}

. Для тестирования теперь можно смоделировать явные зависимости, необходимые для изолированных модульных тестов

public async Task Index_Should_Be_Forbidden() {
    // Arrange
    var authService = Mock.Of<IAuthorizationService>(_ =>
        _.AuthorizeAsync(It.IsAny<ClaimsPrincipal>(), null, It.IsAny<string>()) == 
            Task.FromResult(AuthorizationResult.Failed())
    );

    //Create test user with what ever claims you want
    var displayName = "UnAuthorized User name";
    var identity = new GenericIdentity(displayName);
    var principle = new ClaimsPrincipal(identity);
    // use default context with user
    var httpContext = new DefaultHttpContext() {
        User = principle
    }
    //need these as well for the page context
    var modelState = new ModelStateDictionary();
    var actionContext = new ActionContext(httpContext, new RouteData(), new PageActionDescriptor(), modelState);
    var modelMetadataProvider = new EmptyModelMetadataProvider();
    var viewData = new ViewDataDictionary(modelMetadataProvider, modelState);
    // need page context for the page model
    var pageContext = new PageContext(actionContext) {
        ViewData = viewData
    };
    //create model with necessary dependencies
    var model = new IndexModel(authService) {
        PageContext = pageContext //context includes User 
    };

    //Act
    var result = await model.OnGet();

    //Assert
    result.Should()
        .NotBeNull()
        .And.BeOfType<ForbidResult>();
}

Ссылка Модульные тесты Razor Pages в ASP.NET Core

Вы также, похоже, смешиваете сквозные проблемы, когда речь идет о заявках и авторизации пользователей, но я полагаю, что это выходит за рамки того, чтов настоящее время спрашивается.

Справка Соглашения об авторизации Razor Pages в ASP.NET Core

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...