I'm using SignOutAsync
from Microsoft.AspNetCore.Authentication.AuthenticationHttpContextExtensions.
In my unit tests, I get an ArgumentNullException
somewhere within that extension method, which says
Value cannot be null. (Parameter 'provider')
Message:
System.ArgumentNullException : Value cannot be null. (Parameter 'provider')
Stack Trace:
ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
AuthenticationHttpContextExtensions.SignOutAsync(HttpContext context, String scheme, AuthenticationProperties properties)
AuthenticationHttpContextExtensions.SignOutAsync(HttpContext context, String scheme)
AccountController.SignOut() line 123
AccountControllerTests.MyUnitTest() line 456
--- End of stack trace from previous location ---
I'm not directly providing 'provider', so I assume the extension method is building it from the HttpContext.
The HttpContext in my tests is created using Moq:
var httpContext = new Mock<HttpContext>();
Is there a way I can coax my mock into providing a value for 'provider'? Do I need to switch to a DefaultHttpContext, and provide a value for ServiceScopeFactory
? (Tricky, because DefaultHttpContext isn't mock-able.)
If you look at the source, SignOutAsync
will eventually try to call a private method GetAuthenticationService
, and that tries to call context.RequestServices.GetService<IAuthenticationService>()
.
The generic GetService
is an extension method, so your null provider
really is RequestServices
. RequestServices
is abstract on HttpContext
, so it will be implemented by Moq, and by default on a loose mock, that will simply return null. Oops, there's your crash.
So, could set it up:
IServiceProvider serviceProvider = /*...*/;
httpContext.SetupGet(x => x.RequestServices).Returns(serviceProvider);
But by then you could just use a DefaultHttpContext
and set the provider:
var httpContext = new DefaultHttpContext
{
RequestServices = serviceProvider
};
And now all you need is a service provider. For that, see this question (you can mock one, or create one from a ServiceCollection
, up to you).