繁体   English   中英

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

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

我在我的控制器中添加了一个方法来从HttpContext中的 JWT 令牌中获取用户 ID。 在我的单元测试中, HttpContextnull ,所以我得到了一个异常。

我该如何解决这个问题? 有没有办法起订量HttpContext

这是在我的基础 controller 中获取用户的方法

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

    return "";
}

我的一项测试看起来像这样

[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
    //....
}

在这种特殊情况下,确实没有必要模拟HttpContext

使用DefaultHttpContext并设置完成测试所需的成员

例如

[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
    ....
}

首先,我建议您使用IHttpContextAccessor访问HttpContext并通过Dependency Injection而不是直接使用HttpContext进行注入。 您可以按照此 Microsoft 文档了解IHttpContextAccessor的用法和注入。

使用上面的代码,您的代码将如下所示注入IHttpContextAccessor

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

注入IHttpContextAccessor ,您可以通过this.httpContextAccessor.HttpContext.User.Identity访问身份

所以GetUserId应该改变为

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

    return "";
}

通过上述更改,现在您可以轻松地注入IHttpContextAccessor的模拟进行单元测试。 您可以使用以下代码创建模拟:

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

通过上述设置,在您的测试方法中,您可以在实例化 UsergroupController 的IHttpContextAccessor的同时注入UsergroupController的模拟。

作为@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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM