Skip to content

Commit 7e3f9f2

Browse files
Add section on testing
1 parent 884f7ef commit 7e3f9f2

File tree

2 files changed

+34
-40
lines changed

2 files changed

+34
-40
lines changed

README.md

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -281,43 +281,51 @@ var result = await httpClient.PostAsync<UploadResponse, string>(
281281
);
282282
```
283283

284-
## Testing with Mock HttpClient
284+
## Mocking with Delegating Handlers for Tests
285285

286-
Mock `HttpClient` by creating a fake `IHttpClientFactory` with pattern-matched responses:
286+
Mock HTTP calls by inheriting from `DelegatingHandler` and overriding `SendAsync` ([see Microsoft docs](https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/httpclient-message-handlers)):
287287
288288
```csharp
289-
var factory = FakeHttpClientFactory.CreateMockHttpClientFactory(
290-
response: null, // Use pattern matching for dynamic responses
291-
onRequestSent: request =>
289+
class MockHandler : DelegatingHandler
290+
{
291+
protected override Task<HttpResponseMessage> SendAsync(
292+
HttpRequestMessage request, CancellationToken cancellationToken)
292293
{
293-
// Assert request properties
294-
Assert.Equal("Bearer token", request.Headers.Authorization?.Parameter);
294+
var response = (request.Method.Method, request.RequestUri?.PathAndQuery) switch
295+
{
296+
("GET", "/posts/1") => new HttpResponseMessage(HttpStatusCode.OK)
297+
{
298+
Content = JsonContent.Create(new Post(1, 1, "Title", "Body"))
299+
},
300+
("POST", "/posts") => new HttpResponseMessage(HttpStatusCode.Created)
301+
{
302+
Content = JsonContent.Create(new { Id = 101 })
303+
},
304+
_ => new HttpResponseMessage(HttpStatusCode.NotFound)
305+
};
306+
307+
return Task.FromResult(response);
295308
}
296-
);
297-
298-
// The handler returns responses based on method + URI patterns:
299-
// GET /posts -> 200 OK with post JSON
300-
// POST /posts -> 201 Created
301-
// PUT /posts/1 -> 200 OK
302-
// DELETE /posts/1 -> 200 OK
303-
// * -> 404 Not Found
309+
}
304310

305-
var httpClient = factory.CreateClient();
306-
var result = await httpClient.GetAsync<Post, ErrorResponse>(/* ... */);
311+
// Create HttpClient with mock handler
312+
var httpClient = new HttpClient(new MockHandler());
307313

308-
// Test with exceptions
309-
var exFactory = FakeHttpClientFactory.CreateMockHttpClientFactory(
310-
exceptionToThrow: new HttpRequestException("Network error")
314+
// Make calls - they hit the mock handler
315+
var result = await httpClient.GetAsync(
316+
url: "https://api.example.com/posts/1".ToAbsoluteUrl(),
317+
deserializeSuccess: DeserializePost,
318+
deserializeError: DeserializeError
311319
);
312320

313-
// Test with simulated delays
314-
var delayFactory = FakeHttpClientFactory.CreateMockHttpClientFactory(
315-
simulatedDelay: TimeSpan.FromMilliseconds(500)
316-
);
321+
// Result contains mocked data
322+
result switch
323+
{
324+
OkPost(var post) => Console.WriteLine($"Got mocked post: {post.Title}"),
325+
ErrorPost(var error) => Console.WriteLine($"Error: {error.StatusCode}")
326+
};
317327
```
318328

319-
The fake handler uses a switch expression on `(HttpMethod, Uri)` tuples—extend it for your test scenarios.
320-
321329
## Upgrading from RestClient.Net 6.x
322330

323331
You can continue to use the V6 `IClient` interface with RestClient .Net 7. RestClient.Net 7 is a complete rewrite with a functional architecture. For existing v6 users, **RestClient.Net.Original** provides a polyfill that implements the v6 `IClient` interface using v7 under the hood.

RestClient.sln

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RestClient.Net.OpenApiGener
3737
EndProject
3838
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "RestClient.Net.FsTest", "RestClient.Net.FsTest\RestClient.Net.FsTest.fsproj", "{E9EEE1D7-2A49-4665-8CBA-B0DC22BEB254}"
3939
EndProject
40-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "buh", "buh\buh.csproj", "{4FB10353-67B0-4EE8-A374-F16644CC7A84}"
41-
EndProject
4240
Global
4341
GlobalSection(SolutionConfigurationPlatforms) = preSolution
4442
Debug|Any CPU = Debug|Any CPU
@@ -241,18 +239,6 @@ Global
241239
{E9EEE1D7-2A49-4665-8CBA-B0DC22BEB254}.Release|x64.Build.0 = Release|Any CPU
242240
{E9EEE1D7-2A49-4665-8CBA-B0DC22BEB254}.Release|x86.ActiveCfg = Release|Any CPU
243241
{E9EEE1D7-2A49-4665-8CBA-B0DC22BEB254}.Release|x86.Build.0 = Release|Any CPU
244-
{4FB10353-67B0-4EE8-A374-F16644CC7A84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
245-
{4FB10353-67B0-4EE8-A374-F16644CC7A84}.Debug|Any CPU.Build.0 = Debug|Any CPU
246-
{4FB10353-67B0-4EE8-A374-F16644CC7A84}.Debug|x64.ActiveCfg = Debug|Any CPU
247-
{4FB10353-67B0-4EE8-A374-F16644CC7A84}.Debug|x64.Build.0 = Debug|Any CPU
248-
{4FB10353-67B0-4EE8-A374-F16644CC7A84}.Debug|x86.ActiveCfg = Debug|Any CPU
249-
{4FB10353-67B0-4EE8-A374-F16644CC7A84}.Debug|x86.Build.0 = Debug|Any CPU
250-
{4FB10353-67B0-4EE8-A374-F16644CC7A84}.Release|Any CPU.ActiveCfg = Release|Any CPU
251-
{4FB10353-67B0-4EE8-A374-F16644CC7A84}.Release|Any CPU.Build.0 = Release|Any CPU
252-
{4FB10353-67B0-4EE8-A374-F16644CC7A84}.Release|x64.ActiveCfg = Release|Any CPU
253-
{4FB10353-67B0-4EE8-A374-F16644CC7A84}.Release|x64.Build.0 = Release|Any CPU
254-
{4FB10353-67B0-4EE8-A374-F16644CC7A84}.Release|x86.ActiveCfg = Release|Any CPU
255-
{4FB10353-67B0-4EE8-A374-F16644CC7A84}.Release|x86.Build.0 = Release|Any CPU
256242
EndGlobalSection
257243
GlobalSection(SolutionProperties) = preSolution
258244
HideSolutionNode = FALSE

0 commit comments

Comments
 (0)