【问题标题】:Unit Testing Razor Pages that inherit from a BasePageModel单元测试从 BasePageModel 继承的 Razor 页面
【发布时间】:2019-11-01 07:27:14
【问题描述】:

我有一个 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)。知道我该怎么做吗?

【问题讨论】:

  • 顺便说一句,应该避免通过请求服务使用的服务定位器反模式。通过构造函数注入遵循显式依赖原则。
  • Razor Pages unit tests in ASP.NET Core 也应该对你有用。
  • @Nkosi:我知道这些方法,但由于构造函数位于 BasePageModel 中,而不是当前被测页面的模型中。我希望能够访问该基本构造函数,但无法访问。
  • 您在基模型中没有可供派生类调用的构造函数。您有两个字段和两个属性,但没有基本构造函数

标签: c# unit-testing asp.net-core razor-pages


【解决方案1】:

应避免通过请求服务使用的服务定位器反模式。通过构造函数注入关注Explicit Dependency Principle

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 unit tests in ASP.NET Core

您似乎还混合了涉及用户声明和授权的横切关注点,但我想这超出了当前询问的范围。

参考Razor Pages authorization conventions in ASP.NET Core

【讨论】:

  • 感谢您的参考。在我们的架构中,身份验证确实(并且被处理为)一个横切关注点,但是每页授权足够复杂,以至于它不能作为横切关注点来处理。除了根据不同页面的授权规则允许/禁止访问页面之外,我们还使用授权来显示/隐藏按钮和字段。
  • Nkosi:我在设置 authService 时遇到语法错误:“运算符 '==' 不能应用于 'Task' 和 'AuthorizationResult' 类型的操作数”。我尝试了各种修复,但无法使其正常工作。任何提示将不胜感激。
  • @LaurieDickinson 是我在记事本中徒手写的错字。固定。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-07
  • 2018-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多