Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在Xunit单元测试中使用AuthorizeAsync()测试用户是否具有特定权限_C#_Unit Testing_Asp.net Core Mvc_Xunit.net_Asp.net Core Identity - Fatal编程技术网

C# 在Xunit单元测试中使用AuthorizeAsync()测试用户是否具有特定权限

C# 在Xunit单元测试中使用AuthorizeAsync()测试用户是否具有特定权限,c#,unit-testing,asp.net-core-mvc,xunit.net,asp.net-core-identity,C#,Unit Testing,Asp.net Core Mvc,Xunit.net,Asp.net Core Identity,问题已更新,以便更好地解释我遇到的问题, 只要我有这个控制器 [Authorize] public class IdeaManagementController : Controller { private IIdeaManagementService _ideaManagementService; private ITenantService _tenantService; private ITagService _t

问题已更新,以便更好地解释我遇到的问题,

只要我有这个控制器

    [Authorize]
    public class IdeaManagementController : Controller
    {
        private IIdeaManagementService _ideaManagementService;

        private ITenantService _tenantService;

        private ITagService _tagService;

        private IEmployeeIdeaCategoryService _ideaManagementCategoryService;

        private static PbdModule _modul = PbdModule.IdeaManagement;

        IAuthorizationService _authorizationService;

        public IdeaManagementController(
            IIdeaManagementService ideaManagementService,
            ITenantService tenantService,
            ITagService tagService,
            IAuthorizationService authorizationService,
            IEmployeeIdeaCategoryService ideaManagementCategoryService)
        {
            _ideaManagementService = ideaManagementService;
            _tenantService = tenantService;
            _tagService = tagService;
            _authorizationService = authorizationService;
            _ideaManagementCategoryService = ideaManagementCategoryService;
        }

    public async Task<IActionResult> IdeaCoordinator()
    {
        if (!await _authorizationService.AuthorizeAsync(User, "IdeaManagement_Coordinator"))
        {
            return new ChallengeResult();
        }
        var ideas = _ideaManagementService.GetByIdeaCoordinator(_tenantService.GetCurrentTenantId());
        return View(ideas);
    }
}
我期望得到不同的结果,因为我将返回结果标记为true只是为了忽略这一行代码并继续查看结果,但当我再次调试测试方法时,编译器进入了验证消息,因为它没有感觉到我对AuthorizeAsync方法结果所做的更改。。

事先非常感谢你

==解决方案==

简介:

“我们不能用创造问题的思维水平来解决问题”——阿尔伯特·爱因斯坦。带着这句可爱的话,我想告诉大家,我花了大约一周的时间来解决这个问题,直到我觉得这个问题现在永远也解决不了。我花了几个小时进行调查,但在读了一篇文章,改变了思维方式后,30分钟内就找到了解决办法

问题一目了然:

简单地说,我试图对上面编写的操作方法进行单元测试,我遇到了一个严重的问题,我无法模拟“AuthorizeAsync”方法,因为它是一个内置的扩展方法,而且由于扩展方法本质上是静态方法,所以永远不能用传统的模拟类的方式来模拟它

解决方案详情:

为了能够模拟这个动作方法,我创建了一个包含静态委托的静态类,我将模拟这些委托,或者可以说,通过替换单元测试类中的静态委托来“包装”我的扩展方法,如下所示

public static class DelegateFactory
{
    public static Func<ClaimsPrincipal, object, string, Task<bool>> AuthorizeAsync =
        (c, o, s) =>
        {
            return AuthorizationServiceExtensions.AuthorizeAsync(null, null, "");
        };
}

public Mock<IAuthorizationService> AuthorizationServiceMockExtensionFactory()
{
    var mockRepository = new Moq.MockRepository(Moq.MockBehavior.Strict);
    var mockFactory = mockRepository.Create<IAuthorizationService>();
    var ClaimsPrincipal = mockRepository.Create<ClaimsPrincipal>();
    mockFactory.Setup(x => x.AuthorizeAsync(It.IsAny<ClaimsPrincipal>(), It.IsAny<object>(), It.IsAny<string>())).ReturnsAsync(true);
    return mockFactory;
}
公共静态类DelegateFactory
{
公共静态函数授权异步=
(c、o、s)=>
{
返回AuthorizationServiceExtensions.authorizationAsync(null,null,“”);
};
}
公共模拟授权ServiceMockExtensionFactory()
{
var mockRepository=new Moq.mockRepository(Moq.MockBehavior.Strict);
var mockFactory=mockRepository.Create();
var ClaimsPrincipal=mockRepository.Create();
mockFactory.Setup(x=>x.AuthorizeAsync(It.IsAny(),It.IsAny(),It.IsAny()).ReturnsAsync(true);
返回工厂;
}
在我的测试方法中,我只调用了控制器构造函数实例化中的模拟对象

    [Fact]
    public async void IdeaCoordinator_When_AuthroizedUser_IsNotNull_But_IdeaManagement_Manager_Authorized_Return_View()
    {
       // Arrange
        int approvedByID = data.GetTenantByID(1).TenantId;
        _IdeaManagementControllerObject = new IdeaManagementController
                                          (IdeaManagementServiceMockFactory().Object,
                                          TenantServiceMockFactory().Object,
                                           TagServiceMockFactory().Object,
                                           AuthorizationServiceMockExtensionFactory().Object,
                                           EmployeeIdeaCategoryServiceMockFactory().Object);
        //Act
        IdeaManagementServiceMockFactory().Setup(m => m.GetByIdeaCoordinator(approvedByID)).Returns(data.GetCordinatedEmpIdeas(approvedByID));
        ViewResult _view = await _IdeaManagementControllerObject.IdeaCoordinator() as ViewResult;
        var model = _view.Model as List<EmployeeIdea>;
        // Assert
        Assert.Equal(3, model.Count);
        Assert.IsType(new ViewResult().GetType(), _view);
    }
[事实]
public async void IdeaCoordinator当AuthroizedUser不是null而是ideamaManagement管理器授权返回视图()时
{
//安排
int approvedByID=data.GetTenantByID(1.TenantId);
_IdeaManagementControllerObject=新的IdeaManagementController
(IdeaManagementServiceMockFactory().Object,
TenantServiceMockFactory().Object,
TagServiceMockFactory().Object,
AuthorizationServiceMockExtensionFactory().Object,
EmployeeIdeaCategoryServiceMockFactory().Object);
//表演
IdeaManagementServiceMockFactory().Setup(m=>m.GetByIdeAcominator(approvedByID)).Returns(data.GetCordinatedEmpIdeas(approvedByID));
ViewResult _view=Wait _IdeaManagementControllerObject.IdeaCoordinator()作为ViewResult;
var模型=_view.model as List;
//断言
Assert.Equal(3,model.Count);
Assert.IsType(新视图结果().GetType(),_视图);
}
正如上面所说的,幸福的最大原因是感激。我要感谢斯蒂芬·福卡(Stephen Fuqua)的精彩解决方案和文章


谢谢大家:)

模拟测试所需的依赖项。测试中的方法使用了
IAuthorizationService
iidemanagementservice
ITenantService
。此特定测试不需要任何其他符号

将您的代码耦合到您不拥有和控制的第三方代码会使测试变得困难。我的建议是,在界面后面抽象出你可以控制的东西,这样你就有了灵活性。因此,将
IAuthorizationService
更改为您自己的抽象

public interface ICustomAuthorizationService {
     Task<bool> AuthorizeAsync(ClaimsPrincipal user, string policyName);
}

这是扩展方法的一个缩回示例,因为它们是静态的,如果隐藏依赖项,则很难进行测试。

我在开发ASP.NET核心API时也遇到了这个问题。我的情况不那么复杂,所以不确定同样的解决方案是否适用于您

这是我的解决办法

IAuthorizationService
有两个不是扩展的方法。可以假设(我已经验证)扩展只是助手,并且将调用这些方法中的任何一种

Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable<IAuthorizationRequirement> requirements);
Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName);

要添加到markbeij的答案中,还必须实例化ClaimsPrincipal用户(可能还有其标识),否则将引发空引用异常。这是我遇到的一个问题(ASP.NET Core 5),下面是我对其他遇到此问题的人的解决方案:

// Arrange
var mockAuthorizationService = new Mock<IAuthorizationService>();
mockAuthorizationService
    .Setup(a => a.AuthorizeAsync(It.IsAny<ClaimsPrincipal>(), It.IsAny<object>(), It.IsAny<string>()))
    .ReturnsAsync(AuthorizationResult.Success)
    .Verifiable();

// Instantiate User
var httpContext = new DefaultHttpContext();
httpContext.User = new ClaimsPrincipal();

// Add identity if you need to access the User.Identity
httpContext.User.AddIdentity(new ClaimsIdentity());

controller.ControllerContext = new ControllerContext
{
    HttpContext = httpContext
};

var controller = new AccountController(mockAuthorizationService.Object);

// Act
var result = await controller.Index();

// Assert
mockAuthorizationService.Verify(a => a.AuthorizeAsync(It.IsAny<ClaimsPrincipal>(), It.IsAny<object>(), It.IsAny<string>()), Times.Once);
//排列
var mockAuthorizationService=new Mock();
模拟授权服务
.Setup(a=>a.AuthorizeAsync(It.IsAny(),It.IsAny(),It.IsAny())
.ReturnsAsync(AuthorizationResult.Success)
.可验证();
//实例化用户
var httpContext=new DefaultHttpContext();
httpContext.User=newclaimsprincipal();
//如果需要访问用户,请添加标识。标识
httpContext.User.AddIdentity(new-ClaimsIdentity());
controller.ControllerContext=新的ControllerContext
{
HttpContext=HttpContext
};
var控制器=新的AccountController(mockAuthorizationService.Object);
//表演
var result=await controller.Index();
//断言
验证(a=>a.authorizationAsync(It.IsAny(),It.IsAny(),It.IsAny()),次.Once);

但您的测试需要挑战结果。根据测试方法,在未经授权使用时发生。不清楚您在问什么。显示控制器结构
public class CustomAuthorizationService: ICustomAuthorizationService {
    private readonly IAuthorizationService service;

    public CustomAuthorizationService(IAuthorizationService service) {
        this.service = service;
    }

    public Task<bool> AuthorizeAsync(ClaimsPrincipal user, string policyName) {
        return service.AuthorizeAsync(user, policyName);
    }
}
services.AddSingleton<ICustomAuthorizationService, CustomAuthorizationService>();
[Theory]
[InlineData(1)]
public async void IdeaManager_Should_Return_ViewResult(int _currentTenanatID) {
    // Arrange ..
    var ideaManagementService = new Mock<IIdeaManagementService>();
    var tenantService = new Mock<ITenantService>();
    var authorizationService = new Mock<ICustomAuthorizationService>();
    var sut = new IdeaManagementController(
                     ideaManagementService.Object,
                     tenantService.Object,
                     null,
                     authorizationService.Object,
                     null);

     authorizationService
         .Setup(_ => _.AuthorizeAsync(It.IsAny<ClaimsPrincipal>(), "IdeaManagement_Coordinator"))
         .ReturnsAsync(true);

     tenantService
         .Setup(_ => _.GetCurrentTenantId())
         .Returns(_currentTenanatID);

     var ideas = new //{what ever is your expected return type here}
     ideaManagementService
         .Setup(_ => _.GetByIdeaCoordinator(_currentTenanatID))
         .Returns(ideas);

    // Act 
    var _view = await sut.IdeaCoordinator() as ViewResult;

    // Assert
    Assert.IsNotNull(_view);
    Assert.IsType(typeof(ViewResult), _view);
    Assert.AreEqual(ideas, view.Model);
}
Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable<IAuthorizationRequirement> requirements);
Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName);
var authorizeService = new Mock<IAuthorizationService>();
authorizeService.Setup(service => service.AuthorizeAsync(It.IsAny<ClaimsPrincipal>(), It.IsAny<object>(), It.IsAny<string>())).ReturnsAsync(AuthorizationResult.Success);
// Arrange
var mockAuthorizationService = new Mock<IAuthorizationService>();
mockAuthorizationService
    .Setup(a => a.AuthorizeAsync(It.IsAny<ClaimsPrincipal>(), It.IsAny<object>(), It.IsAny<string>()))
    .ReturnsAsync(AuthorizationResult.Success)
    .Verifiable();

// Instantiate User
var httpContext = new DefaultHttpContext();
httpContext.User = new ClaimsPrincipal();

// Add identity if you need to access the User.Identity
httpContext.User.AddIdentity(new ClaimsIdentity());

controller.ControllerContext = new ControllerContext
{
    HttpContext = httpContext
};

var controller = new AccountController(mockAuthorizationService.Object);

// Act
var result = await controller.Index();

// Assert
mockAuthorizationService.Verify(a => a.AuthorizeAsync(It.IsAny<ClaimsPrincipal>(), It.IsAny<object>(), It.IsAny<string>()), Times.Once);