【问题标题】:how to mock AuthenticateAsync on AspNetCore.Authentication.Abstractions如何在 AspNetCore.Authentication.Abstractions 上模拟 AuthenticateAsync
【发布时间】:2025-12-01 08:05:01
【问题描述】:

我在一个控制器上有一个动作,它调用了

var result = await HttpContext.AuthenticateAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);

我试图在这样的单元测试中模拟这个结果

httpContextMock.AuthenticateAsync(Arg.Any<string>()).Returns(AuthenticateResult.Success(...

但是,这会引发InvalidOperationException

“没有注册类型‘Microsoft.AspNetCore.Authentication.IAuthenticationService’的服务”

模拟这个方法的正确方法是什么?

【问题讨论】:

    标签: c# unit-testing asp.net-core mocking nsubstitute


    【解决方案1】:

    那个extension method

    /// <summary>
    /// Extension method for authenticate.
    /// </summary>
    /// <param name="context">The <see cref="HttpContext"/> context.</param>
    /// <param name="scheme">The name of the authentication scheme.</param>
    /// <returns>The <see cref="AuthenticateResult"/>.</returns>
    public static Task<AuthenticateResult> AuthenticateAsync(this HttpContext context, string scheme) =>
        context.RequestServices.GetRequiredService<IAuthenticationService>().AuthenticateAsync(context, scheme);
    

    通过IServiceProvider RequestServices 属性。

    /// <summary>
    /// Gets or sets the <see cref="IServiceProvider"/> that provides access to the request's service container.
    /// </summary>
    public abstract IServiceProvider RequestServices { get; set; }
    

    模拟服务提供商以返回模拟的IAuthenticationService,您应该能够通过测试伪造自己的方式。

    authServiceMock.AuthenticateAsync(Arg.Any<HttpContext>(), Arg.Any<string>())
        .Returns(Task.FromResult(AuthenticateResult.Success()));
    providerMock.GetService(typeof(IAuthenticationService))
        .Returns(authServiceMock);
    httpContextMock.RequestServices.Returns(providerMock);
    
    //...
    

    【讨论】:

    • 谢谢。我没有注意到返回模拟服务的 RequestServices 方法。干杯。
    • 不确定这是什么版本的 .NET,但使用 3.1 版我收到以下错误“无法从用法中推断方法 'Task.FromResult(TResult)' 的类型争论. 尝试明确指定类型参数。
    • 我可以将方法更改为FromResult&lt;AuthenticateResult&gt;(AuthenticateResult.Success),但随后出现错误“无法从方法组转换为 ActionResult(为时已晚,无法进一步详细编辑)