简体   繁体   English

xunit - 如何在单元测试中获取 HttpContext.User.Identity

[英]xunit - how to get HttpContext.User.Identity in unit tests

I added a method to my controllers to get the user-id from the JWT token in the HttpContext .我在我的控制器中添加了一个方法来从HttpContext中的 JWT 令牌中获取用户 ID。 In my unit tests the HttpContext is null , so I get an exception.在我的单元测试中, HttpContextnull ,所以我得到了一个异常。

How can I solve the problem?我该如何解决这个问题? Is there a way to moq the HttpContext ?有没有办法起订量HttpContext

Here is the method to get the user in my base controller这是在我的基础 controller 中获取用户的方法

protected string GetUserId()
{
    if (HttpContext.User.Identity is ClaimsIdentity identity)
    {
        IEnumerable<Claim> claims = identity.Claims;
        return claims.ToList()[0].Value;
    }

    return "";
}

One of my tests look like this我的一项测试看起来像这样

[Theory]
[MemberData(nameof(TestCreateUsergroupItemData))]
public async Task TestPostUsergroupItem(Usergroup usergroup)
{
    // Arrange
    UsergroupController controller = new UsergroupController(context, mapper);

    // Act
    var controllerResult = await controller.Post(usergroup).ConfigureAwait(false);

    // Assert
    //....
}

There really is no need to have to mock the HttpContext in this particular case.在这种特殊情况下,确实没有必要模拟HttpContext

Use the DefaultHttpContext and set the members necessary to exercise the test to completion使用DefaultHttpContext并设置完成测试所需的成员

For example例如

[Theory]
[MemberData(nameof(TestCreateUsergroupItemData))]
public async Task TestPostUsergroupItem(Usergroup usergroup) {
    // Arrange

    //...

    var identity = new GenericIdentity("some name", "test");
    var contextUser = new ClaimsPrincipal(identity); //add claims as needed

    //...then set user and other required properties on the httpContext as needed
    var httpContext = new DefaultHttpContext() {
        User = contextUser;
    };

    //Controller needs a controller context to access HttpContext
    var controllerContext = new ControllerContext() {
        HttpContext = httpContext,
    };
    //assign context to controller
    UsergroupController controller = new UsergroupController(context, mapper) {
        ControllerContext = controllerContext,
    };

    // Act
    var controllerResult = await controller.Post(usergroup).ConfigureAwait(false);

    // Assert
    ....
}

First of all, I would suggest you to use IHttpContextAccessor to access HttpContext and inject via Dependency Injection instead of using HttpContext directly.首先,我建议您使用IHttpContextAccessor访问HttpContext并通过Dependency Injection而不是直接使用HttpContext进行注入。 You can follow this Microsoft documentation to understand usage and injection of IHttpContextAccessor .您可以按照此 Microsoft 文档了解IHttpContextAccessor的用法和注入。

With the above code, your code will looks as follows to inject IHttpContextAccessor使用上面的代码,您的代码将如下所示注入IHttpContextAccessor

private IHttpContextAccessor  httpContextAccessor;
public class UsergroupController(IHttpContextAccessor httpContextAccessor, ...additional parameters)
{
   this.httpContextAccessor = httpContextAccessor;
   //...additional assignments
}

Once IHttpContextAccessor is injected, you can access the Identity as this.httpContextAccessor.HttpContext.User.Identity注入IHttpContextAccessor ,您可以通过this.httpContextAccessor.HttpContext.User.Identity访问身份

So the GetUserId should change as所以GetUserId应该改变为

protected string GetUserId()
{
    if (this.httpContextAccessor.HttpContext.User.Identity is ClaimsIdentity identity)
    {
        IEnumerable<Claim> claims = identity.Claims;
        return claims.ToList()[0].Value;
    }

    return "";
}

With above change, now you can easily inject the mock of IHttpContextAccessor for unit testing.通过上述更改,现在您可以轻松地注入IHttpContextAccessor的模拟进行单元测试。 You can use the below code to create the mock:您可以使用以下代码创建模拟:

private static ClaimsPrincipal user = new ClaimsPrincipal(
                        new ClaimsIdentity(
                            new Claim[] { new Claim("MyClaim", "MyClaimValue") },
                            "Basic")
                        );


private static Mock<IHttpContextAccessor> GetHttpContextAccessor()
{
        var httpContextAccessorMock = new Mock<IHttpContextAccessor>();
        httpContextAccessorMock.Setup(h => h.HttpContext.User).Returns(user);
        return httpContextAccessorMock;
}

With the above setup, in your test method, you can inject the mock of IHttpContextAccessor while instantiating the object of UsergroupController .通过上述设置,在您的测试方法中,您可以在实例化 UsergroupController 的IHttpContextAccessor的同时注入UsergroupController的模拟。

As a follow up to the comment by @Nkosi: there's no requirement to DI the context as you can set it during testing like so:作为@Nkosi评论的后续:不需要DI上下文,因为您可以在测试期间设置它,如下所示:

var identity = new GenericIdentity("some name", "test");
var contextUser = new ClaimsPrincipal(identity); 
controller.ControllerContext = new ControllerContext
{
    HttpContext = new DefaultHttpContext { User = contextUser }
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在ASP.NET MVC中扩展HttpContext.User.Identity - extend HttpContext.User.Identity in asp.net mvc .NET 核心 Web API HttpContext.User.Claims 和 HttpContext.User.Identity 在控制器中总是 null - .NET Core Web API HttpContext.User.Claims and HttpContext.User.Identity are always null in Controllers HttpContext.User.Identity 中缺少组内置管理员(SID:S-1-5-32-544) - Missing Group Built-in Administrators (SID: S-1-5-32-544) in HttpContext.User.Identity 我们可以扩展HttpContext.User.Identity在asp.net中存储更多数据吗? - Can we extend HttpContext.User.Identity to store more data in asp.net? Xunit 单元测试不会运行 - Xunit Unit Tests will not run 如何伪造HttpContext进行单元测试? - How can I fake HttpContext for unit tests? 适用于MassTransit使用者的XUnit单元测试 - XUnit unit tests for MassTransit consumer OpenRasta在单元测试中模拟HttpContext - OpenRasta Mocking HttpContext in Unit Tests 在这种特定情况下,如何使用Moq和xUnit添加单元测试? - How to add unit tests using Moq and xUnit in this specific scenario? 无法获取HttpContext.Current.User.Identity来返回值 - Cant get HttpContext.Current.User.Identity to return values
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM