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

Hen*_*ing 6 c# unit-testing xunit .net-core

我向控制器添加了一个方法,以从中的JWT令牌获取用户ID HttpContext。在我的单元测试中,nullHttpContextnull,因此出现异常。

我该如何解决这个问题?有没有一种方法来起订量HttpContext

这是使用户进入我的基本控制器的方法

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

    return "";
}
Run Code Online (Sandbox Code Playgroud)

我的一项测试如下所示

[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
    //....
}
Run Code Online (Sandbox Code Playgroud)

use*_*994 6

首先,我建议你使用viaIHttpContextAccessor来访问HttpContext和注入,Dependency Injection而不是HttpContext直接使用。您可以按照此 Microsoft 文档来了解IHttpContextAccessor.

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

private IHttpContextAccessor  httpContextAccessor;
public class UsergroupController(IHttpContextAccessor httpContextAccessor, ...additional parameters)
{
   this.httpContextAccessor = httpContextAccessor;
   //...additional assignments
}
Run Code Online (Sandbox Code Playgroud)

注入后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 "";
}
Run Code Online (Sandbox Code Playgroud)

通过上述更改,现在您可以轻松注入模拟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;
}
Run Code Online (Sandbox Code Playgroud)

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

  • 控制器已经可以访问“HttpContext”。“IHttpContextAccessor”旨在在控制器外部使用。 (2认同)

Nko*_*osi 5

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
    ....
}
Run Code Online (Sandbox Code Playgroud)