gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-30 14:23:59 25 4
gpt4 key购买 nike

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

只要我有这个 Controller ,

    [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);
}
}

只是我需要测试操作方法 IdeaCoordinator 的 retrned viewResult 但我不能简单地因为如果 _authorizationService.AuthorizeAsync 验证方法,我试图模拟该方法但我不能因为它是一个扩展内置方法,然后我尝试通过创建一个实现 IAuthorizationService 的新接口(interface)和 Mock 这样的自定义接口(interface)来解决解决方案

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


public IAuthorizationService CustomAuthorizationServiceFactory()
{
Mock<ICustomAuthorizationService> _custom = new Mock<ICustomAuthorizationService>();
_custom.Setup(c => c.AuthorizeAsync(It.IsAny<ClaimsPrincipal>(), "IdeaManagement_Coordinator")).ReturnsAsync(true);
return _custom.Object;
}

并在我调用 Controller 构造函数时将其注入(inject),然后我发现自己就是这样:

[Theory]
[InlineData(1)]
public async void IdeaManager_Should_Return_ViewResult(int _currentTenanatID)
{
// Arrange ..
_IdeaManagementControllerObject = new IdeaManagementController
(IdeaManagementServiceMockFactory(_currentTenanatID),
TenantServiceMockFactory(_currentTenanatID),
TagServiceMockFactory(),
AuthorizationServiceMockFactory(),
EmployeeIdeaCategoryServiceMockFactory());
// Act
var _view = await _IdeaManagementControllerObject.IdeaCoordinator() as ViewResult;

// Assert
Assert.IsType(new ViewResult().GetType(), _view);
}

我期望得到不同的结果,因为我将返回结果标记为 true 只是为了忽略这行代码并继续查看 Viewresult,但是当我再次调试我的测试方法时,编译器进入了验证消息,因为它没有感觉到我对 AuthorizeAsync 方法结果所做的更改.. enter image description here

非常感谢您。

==解决方案==

简介:

“我们无法用创造问题的相同思维水平来解决问题”——阿尔伯特·爱因斯坦。用这句可爱的话说,我想告诉你,我花了大约 1 周的时间来解决这个问题,直到我觉得这一刻永远无法解决,我花了几个小时进行调查,但是在阅读了一篇文章并改变了思维方式之后,解决方案在 30 分钟内出现。

问题一览:

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

详细解决方案:

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

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;
}

在我的测试方法中,我只是在 Controller 构造函数实例化中调用了模拟对象。

    [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);
}

正如它所说,幸福的最大原因是感恩。我要感谢 Stephen Fuqua 出色的解决方案和文章,http://www.safnet.com/writing/tech/2014/04/making-mockery-of-extension-methods.html

谢谢大家:)!

最佳答案

模拟测试所需的依赖项。被测方法使用了 IAuthorizationServiceIIdeaManagementServiceITenantService。此特定测试不需要其他所有内容。

将您的代码与您不拥有和控制的第 3 方代码耦合会增加测试难度。我的建议是在你控制的接口(interface)后面抽象它,这样你就有了灵 active 。因此,为您自己的抽象更改 IAuthorizationService

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

实现将包装使用扩展方法的实际授权服务

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>();

如果身份已添加到服务集合中,则 IAuthorizationService 将在解析后注入(inject)到您的自定义服务中。

现在对于您的测试,您可以模拟您控制的接口(interface),而不必担心破坏第 3 方代码。

[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);
}

这是扩展方法缺点的一个例子,因为它们是静态的,如果它们隐藏了依赖关系则很难测试。

关于c# - 在 Xunit 单元测试中使用 AuthorizeAsync() 测试用户是否具有特定权限,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42965727/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com