I'd like to amend @Peter CSala's answer some, since it got me most of the way there but not entirely. My service class uses the IHttpClientFactory but without any named client. When setting up the above code and running as is, I'm met with an exception:
Message:
System.NotSupportedException : Unsupported expression: factory => factory.CreateClient()
Extension methods (here: HttpClientFactoryExtensions.CreateClient) may not be used in setup / verification expressions.
Stack Trace:
Guard.IsOverridable(MethodInfo method, Expression expression) line 87
ExpressionExtensions.<Split>g__Split|5_0(Expression e, Expression& r, MethodExpectation& p, Boolean assignment, Boolean allowNonOverridableLastProperty) line 234
ExpressionExtensions.Split(LambdaExpression expression, Boolean allowNonOverridableLastProperty) line 149
Mock.SetupRecursive[TSetup](Mock mock, LambdaExpression expression, Func`4 setupLast, Boolean allowNonOverridableLastProperty) line 643
Mock.Setup(Mock mock, LambdaExpression expression, Condition condition) line 498
Mock`1.Setup[TResult](Expression`1 expression) line 452
MyServiceTests.GetHttpClientFactoryMock(Int64 contentLength) line 84
MyServiceTests.DoesCopy_PutObject() line 55
GenericAdapter`1.GetResult()
AsyncToSyncAdapter.Await(Func`1 invoke)
TestMethodCommand.RunTestMethod(TestExecutionContext context)
TestMethodCommand.Execute(TestExecutionContext context)
<>c__DisplayClass1_0.<Execute>b__0()
DelegatingTestCommand.RunTestMethodInThreadAbortSafeZone(TestExecutionContext context, Action action)
This is because the parameter-less call to IHttpClientFactory.CreateClient() is actually an extension method, where the method call for a named client is not. Looking into the extension method, it actually is just a convenience wrapper for the named client method using a default name from Microsoft.Extensions.Options.
All you have to do is actually mock the named client method to return the mocked HttpClient from Peter's example above when requesting the default name. Here is the entire code I used to mock the IHttpClientFactory to work with a default client and workaround the above exception:
using Microsoft.Extensions.Options;
var mockHandler = new Mock<DelegatingHandler>();
mockHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.OK)
.Verifiable();
mockHandler.As<IDisposable>().Setup(s => s.Dispose());
var httpClient = new HttpClient(mockHandler.Object);
var mockFactory = new Mock<IHttpClientFactory>(MockBehavior.Strict);
mockFactory
.Setup(factory => factory.CreateClient(Options.DefaultName))
.Returns(httpClient)
.Verifiable();
// Use the factory from above in your tests
// Calls in the service to IHttpClientFactory.CreateClient() will
// return the HttpClient using the mocked handler from above :)
var res = myService.DoTheThing(mockFactory.Object);
ServiceCollectionby hand is suboptimal. If you want to perform unit testing then you need to Mock theIHttpClientFactoryand all related stuff, just as I described in my proposed solution.