Skip to content

Commit 53db122

Browse files
authored
Add CreateClient methods to TestableHttpMessageHandler
The following methods are added: - `TestableHttpMessageHandlerExtension.CreateClient(this TestableHttpMessageHandler)` - `TestableHttpMessageHandlerExtension.CreateClient(this TestableHttpMessageHandler, Action<HttpClient>)` Fixes #21.
1 parent 7278c11 commit 53db122

File tree

5 files changed

+181
-0
lines changed

5 files changed

+181
-0
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using System;
2+
using System.Net.Http;
3+
4+
namespace TestableHttpClient
5+
{
6+
public static class TestableHttpMessageHandlerExtensions
7+
{
8+
/// <summary>
9+
/// Create an <seealso cref="HttpClient"/> configured with the TestableHttpMessageHandler.
10+
/// </summary>
11+
/// <param name="handler">The TestableHttpMessageHandler to set on the client.</param>
12+
/// <returns>An HttpClient configure with the TestableHttpMessageHandler.</returns>
13+
/// <exception cref="ArgumentNullException">The `handler` is `null`</exception>
14+
/// <remarks>Using this method is equivalent to `new HttClient(handler)`.</remarks>
15+
public static HttpClient CreateClient(this TestableHttpMessageHandler handler)
16+
{
17+
return CreateClient(handler, _ => { });
18+
}
19+
20+
/// <summary>
21+
/// Create and configure an <seealso cref="HttpClient"/> configured with the TestableHttpMessageHandler.
22+
/// </summary>
23+
/// <param name="handler">The TestableHttpMessageHandler to set on the client.</param>
24+
/// <param name="configureClient">A delegate that is used to configure an HttpClient</param>
25+
/// <returns>An HttpClient configure with the TestableHttpMessageHandler.</returns>
26+
/// <exception cref="ArgumentNullException">The `handler` or `configureClient` is `null`</exception>
27+
public static HttpClient CreateClient(this TestableHttpMessageHandler handler, Action<HttpClient> configureClient)
28+
{
29+
if (handler is null)
30+
{
31+
throw new ArgumentNullException(nameof(handler));
32+
}
33+
34+
if (configureClient is null)
35+
{
36+
throw new ArgumentNullException(nameof(configureClient));
37+
}
38+
39+
var httpClient = new HttpClient(handler);
40+
configureClient(httpClient);
41+
42+
return httpClient;
43+
}
44+
}
45+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using System.Net;
2+
using System.Threading.Tasks;
3+
4+
using Xunit;
5+
6+
namespace TestableHttpClient.IntegrationTests
7+
{
8+
public class CreatingClients
9+
{
10+
[Fact]
11+
public async Task CreateASimpleHttpClient()
12+
{
13+
var testableHttpMessageHandler = new TestableHttpMessageHandler();
14+
var client = testableHttpMessageHandler.CreateClient();
15+
16+
await client.GetAsync("https://httpbin.org/get");
17+
18+
testableHttpMessageHandler.ShouldHaveMadeRequests().WithHttpVersion(HttpVersion.Version11);
19+
}
20+
21+
[Fact]
22+
public async Task CreateClientWithConfiguration()
23+
{
24+
var testableHttpMessageHandler = new TestableHttpMessageHandler();
25+
var client = testableHttpMessageHandler.CreateClient(client => client.DefaultRequestVersion = HttpVersion.Version20);
26+
27+
await client.GetAsync("https://httpbin.org/get");
28+
29+
testableHttpMessageHandler.ShouldHaveMadeRequests().WithHttpVersion(HttpVersion.Version20);
30+
}
31+
}
32+
}

test/TestableHttpClient.Tests/TestableHttpClient.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
1111
</PackageReference>
1212
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
13+
<PackageReference Include="Moq" Version="4.14.1" />
1314
<PackageReference Include="xunit" Version="2.4.1" />
1415
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
1516
<PrivateAssets>all</PrivateAssets>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using System;
2+
using System.Net.Http;
3+
using System.Reflection;
4+
5+
using Xunit;
6+
7+
namespace TestableHttpClient.Tests
8+
{
9+
public partial class TestableHttpMessageHandlerExtensionsTests
10+
{
11+
#nullable disable
12+
[Fact]
13+
public void CreateClient_NullTestableHttpMessageHandler_ThrowsArgumentNullException()
14+
{
15+
TestableHttpMessageHandler sut = null;
16+
17+
var exception = Assert.Throws<ArgumentNullException>(() => sut.CreateClient());
18+
Assert.Equal("handler", exception.ParamName);
19+
}
20+
#nullable restore
21+
22+
[Fact]
23+
public void CreateClient_CorrectTestableHttpMessageHandler_AddsHandlerToHttpClient()
24+
{
25+
using var sut = new TestableHttpMessageHandler();
26+
27+
using var client = sut.CreateClient();
28+
29+
var handler = GetPrivateHandler(client);
30+
31+
Assert.Same(sut, handler);
32+
}
33+
34+
private static object? GetPrivateHandler(HttpClient client)
35+
{
36+
var handlerField = client.GetType().BaseType?.GetField("_handler", BindingFlags.Instance | BindingFlags.NonPublic);
37+
if (handlerField == null)
38+
{
39+
Assert.True(false, "Can't find the private _handler field on HttpClient.");
40+
return null;
41+
}
42+
return handlerField.GetValue(client);
43+
}
44+
}
45+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using System;
2+
using System.Net.Http;
3+
4+
using Moq;
5+
6+
using Xunit;
7+
8+
namespace TestableHttpClient.Tests
9+
{
10+
public partial class TestableHttpMessageHandlerExtensionsTests
11+
{
12+
#nullable disable
13+
[Fact]
14+
public void CreateClientWithConfigurer_NullTestableHttpMessageHandler_ThrowsArgumentNullException()
15+
{
16+
TestableHttpMessageHandler sut = null;
17+
Action<HttpClient> configureClient = client => { };
18+
19+
var exception = Assert.Throws<ArgumentNullException>(() => sut.CreateClient(configureClient));
20+
Assert.Equal("handler", exception.ParamName);
21+
}
22+
23+
[Fact]
24+
public void CreateClientWithConfigurer_NullConfigureAction_ThrowsArgumentNullException()
25+
{
26+
using var sut = new TestableHttpMessageHandler();
27+
Action<HttpClient> configureClient = null;
28+
29+
var exception = Assert.Throws<ArgumentNullException>(() => sut.CreateClient(configureClient));
30+
Assert.Equal("configureClient", exception.ParamName);
31+
}
32+
#nullable restore
33+
34+
[Fact]
35+
public void CreateClientWithConfigurer_ReturnsHttpClientWithHandlerConfigured()
36+
{
37+
using var sut = new TestableHttpMessageHandler();
38+
Action<HttpClient> configureClient = client => { };
39+
40+
using var client = sut.CreateClient(configureClient);
41+
42+
var handler = GetPrivateHandler(client);
43+
44+
Assert.Same(sut, handler);
45+
}
46+
47+
[Fact]
48+
public void CreateClientWithConfigurer_CallsConfigureClientWithClientToReturn()
49+
{
50+
using var sut = new TestableHttpMessageHandler();
51+
Mock<Action<HttpClient>> configureClient = new Mock<Action<HttpClient>>();
52+
53+
using var client = sut.CreateClient(configureClient.Object);
54+
55+
configureClient.Verify(x => x.Invoke(client), Times.Once);
56+
}
57+
}
58+
}

0 commit comments

Comments
 (0)