5

i have an action on a controller which calls

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

i'm trying to mock this result in a unit test like so

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

however that throws an InvalidOperationException

"No service for type 'Microsoft.AspNetCore.Authentication.IAuthenticationService' has been registered"

what is the correct way to mock this method?

Nkosi
  • 235,767
  • 35
  • 427
  • 472
ryanthescot
  • 327
  • 4
  • 16

1 Answers1

9

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

goes through the IServiceProvider RequestServices property.

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

Mock the service provider to return a mocked IAuthenticationService and you should be able to fake your way through the test.

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

//...
Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • thanks for that. i hadnt noticed the RequestServices method to return the mocked services. cheers. – ryanthescot Oct 31 '17 at 16:06
  • Not certain what version of .NET this is, but using version 3.1 I get the following error "The type arguemtn fro method 'Task.FromResult(TResult)' cannot be inferred from the usage. Try Specifying the type arguments explicitly. – obiwankoban Mar 01 '20 at 17:15
  • I can change the method to `FromResult(AuthenticateResult.Success)` but then I get an error 'cannot convert from method group to ActionResult (too late to edit in further details) – obiwankoban Mar 01 '20 at 17:28