diff --git a/Mockly.ApiVerificationTests/ApprovedApi/net472.verified.txt b/Mockly.ApiVerificationTests/ApprovedApi/net472.verified.txt index e41d11f..95cac9a 100644 --- a/Mockly.ApiVerificationTests/ApprovedApi/net472.verified.txt +++ b/Mockly.ApiVerificationTests/ApprovedApi/net472.verified.txt @@ -42,6 +42,7 @@ namespace Mockly public Mockly.RequestMockBuilder ForPut(string urlPattern) { } public System.Net.Http.HttpClient GetClient() { } public System.Net.Http.IHttpClientFactory GetClientFactory() { } + public System.Net.Http.HttpMessageHandler GetMessageHandler() { } public System.Collections.Generic.IEnumerable GetUninvokedMocks() { } public Mockly.HttpMock Reset() { } } diff --git a/Mockly.ApiVerificationTests/ApprovedApi/net8.0.verified.txt b/Mockly.ApiVerificationTests/ApprovedApi/net8.0.verified.txt index b2b4b6c..bd31e56 100644 --- a/Mockly.ApiVerificationTests/ApprovedApi/net8.0.verified.txt +++ b/Mockly.ApiVerificationTests/ApprovedApi/net8.0.verified.txt @@ -44,6 +44,7 @@ namespace Mockly public Mockly.RequestMockBuilder ForPut(string urlPattern) { } public System.Net.Http.HttpClient GetClient() { } public System.Net.Http.IHttpClientFactory GetClientFactory() { } + public System.Net.Http.HttpMessageHandler GetMessageHandler() { } public System.Collections.Generic.IEnumerable GetUninvokedMocks() { } public Mockly.HttpMock Reset() { } } diff --git a/Mockly.Specs/HttpMockSpecs.cs b/Mockly.Specs/HttpMockSpecs.cs index 717f9cf..7b630b7 100644 --- a/Mockly.Specs/HttpMockSpecs.cs +++ b/Mockly.Specs/HttpMockSpecs.cs @@ -1684,6 +1684,27 @@ public async Task GetClientFactory_creates_clients_using_the_mock_handler() } } + public class WhenGettingMessageHandler + { + [Fact] + public async Task Can_return_a_message_handler_that_intercepts_requests() + { + var mock = new HttpMock(); + mock.ForGet().WithPath("/ping").RespondsWithStatus(HttpStatusCode.OK); + + var handler = mock.GetMessageHandler(); + + using var client = new HttpClient(handler) + { + BaseAddress = new Uri("https://localhost/") + }; + + var response = await client.GetAsync("/ping"); + + response.Should().Be200Ok(); + } + } + public class RespondingWithHttpContent { [Fact] diff --git a/Mockly/HttpMock.cs b/Mockly/HttpMock.cs index 44b95d5..f032256 100644 --- a/Mockly/HttpMock.cs +++ b/Mockly/HttpMock.cs @@ -227,6 +227,18 @@ public IHttpClientFactory GetClientFactory() return new MockHttpClientFactory(this); } + /// + /// Gets the underlying that intercepts HTTP requests based on the configured mocks. + /// Use this when you need to wire the mock handler directly into an or other infrastructure + /// that accepts an . + /// + [SuppressMessage("Design", "CA1024:Use properties where appropriate", + Justification = "GetMessageHandler creates resources and should not be a property")] + public HttpMessageHandler GetMessageHandler() + { + return new MockHttpMessageHandler(this); + } + internal void AddMock(RequestMock mock) { mocks.Add(mock); diff --git a/website/docs/quick-start.md b/website/docs/quick-start.md index 59ffded..b4d877d 100644 --- a/website/docs/quick-start.md +++ b/website/docs/quick-start.md @@ -65,6 +65,21 @@ var response = await client.GetAsync("/ping"); response.StatusCode.Should().Be(HttpStatusCode.OK); ``` +## Using a Raw HttpMessageHandler + +If your code accepts an `HttpMessageHandler` directly (for example, when constructing `HttpClient` yourself or integrating with custom infrastructure), Mockly can provide the underlying handler: + +```csharp +var mock = new HttpMock(); +mock.ForGet().WithPath("/ping").RespondsWithStatus(HttpStatusCode.OK); + +HttpMessageHandler handler = mock.GetMessageHandler(); +var client = new HttpClient(handler) { BaseAddress = new Uri("https://localhost/") }; + +var response = await client.GetAsync("/ping"); +response.StatusCode.Should().Be(HttpStatusCode.OK); +``` + ## Complete Example Here's a more comprehensive example showing multiple features: diff --git a/website/docs/usage.md b/website/docs/usage.md index 1f743ae..a29f55c 100644 --- a/website/docs/usage.md +++ b/website/docs/usage.md @@ -26,6 +26,27 @@ mock.ForGet() HttpClient client = mock.GetClient(); // BaseAddress defaults to https://localhost/ ``` +## Getting an HttpClient, IHttpClientFactory or HttpMessageHandler + +Mockly provides three ways to wire the mock into your code under test: + +- **`GetClient()`** — returns a new `HttpClient` with `BaseAddress` set to `https://localhost/`, ready to use directly in tests. +- **`GetClientFactory()`** — returns an `IHttpClientFactory` whose `CreateClient()` method produces `HttpClient` instances backed by the mock. Use this when your code depends on `IHttpClientFactory`. +- **`GetMessageHandler()`** — returns the underlying `HttpMessageHandler`. Use this when you need to build a custom `HttpClient` or pass the handler to other infrastructure. + +```csharp +// Option 1: HttpClient (BaseAddress defaults to https://localhost/) +HttpClient client = mock.GetClient(); + +// Option 2: IHttpClientFactory +IHttpClientFactory factory = mock.GetClientFactory(); +HttpClient clientFromFactory = factory.CreateClient("myClient"); + +// Option 3: HttpMessageHandler +HttpMessageHandler handler = mock.GetMessageHandler(); +var customClient = new HttpClient(handler) { BaseAddress = new Uri("https://localhost/") }; +``` + ## HTTP Method Support Mockly supports all common HTTP methods: