Skip to content

Commit ee96b31

Browse files
committed
Replace NSubstitute with a small amount of custom mocks
1 parent b0a987d commit ee96b31

File tree

5 files changed

+44
-55
lines changed

5 files changed

+44
-55
lines changed

test/TestableHttpClient.Tests/HttpRequestMessageAsserterTests/WithRequestUri.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ public void WithNonMatchingRequestUri_ThrowsHttpRequestMessageAssertionException
3737
using HttpRequestMessage request = new(HttpMethod.Get, "https://example.com");
3838
HttpRequestMessageAsserter sut = new([request]);
3939

40-
Assert.Throws<HttpRequestMessageAssertionException>(() => sut.WithRequestUri("https://no-op.com/"));
40+
var exception = Assert.Throws<HttpRequestMessageAssertionException>(() => sut.WithRequestUri("https://no-op.com/"));
41+
4142
}
4243

4344

test/TestableHttpClient.Tests/TestableHttpClient.Tests.csproj

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,6 @@
99
<PackageReference Include="System.Net.Http.Json" Version="8.0.1" />
1010
</ItemGroup>
1111

12-
<ItemGroup>
13-
<PackageReference Include="NSubstitute" Version="5.3.0" />
14-
<PackageReference Include="NSubstitute.Analyzers.CSharp" Version="1.0.17">
15-
<PrivateAssets>all</PrivateAssets>
16-
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
17-
</PackageReference>
18-
</ItemGroup>
19-
2012
<ItemGroup>
2113
<ProjectReference Include="..\..\src\TestableHttpClient\TestableHttpClient.csproj" />
2214
</ItemGroup>

test/TestableHttpClient.Tests/TestableHttpMessageHandlerExtensionsTests/CreateClientWithConfigurer.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
using NSubstitute;
2-
3-
namespace TestableHttpClient.Tests;
1+
namespace TestableHttpClient.Tests;
42

53
public partial class TestableHttpMessageHandlerExtensionsTests
64
{
@@ -63,11 +61,12 @@ public void CreateClientWithConfigurer_WhenConfiguringBaseAddress_DoesNotOverrid
6361
[Fact]
6462
public void CreateClientWithConfigurer_CallsConfigureClientWithClientToReturn()
6563
{
64+
HttpClient? capturedClient= null;
6665
using TestableHttpMessageHandler sut = new();
67-
Action<HttpClient> configureClient = Substitute.For<Action<HttpClient>>();
66+
void configureClient(HttpClient client) => capturedClient = client;
6867

6968
using var client = sut.CreateClient(configureClient);
7069

71-
configureClient.Received(1).Invoke(client);
70+
Assert.Same(client, capturedClient);
7271
}
7372
}
Lines changed: 23 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
using NSubstitute;
2-
3-
namespace TestableHttpClient.Tests;
1+
namespace TestableHttpClient.Tests;
42

53
public partial class TestableHttpMessageHandlerExtensionsTests
64
{
@@ -10,9 +8,8 @@ public void CreateClientWithConfigurerAndHttpMessageHandlers_NullTestableHttpMes
108
TestableHttpMessageHandler sut = null!;
119

1210
static void configureClient(HttpClient _) { }
13-
var handlers = Enumerable.Empty<DelegatingHandler>();
14-
15-
var exception = Assert.Throws<ArgumentNullException>(() => sut.CreateClient(configureClient, handlers));
11+
12+
var exception = Assert.Throws<ArgumentNullException>(() => sut.CreateClient(configureClient, []));
1613
Assert.Equal("handler", exception.ParamName);
1714
}
1815

@@ -21,9 +18,8 @@ public void CreateClientWithConfigurerAndHttpMessageHandlers_NullConfigureAction
2118
{
2219
using TestableHttpMessageHandler sut = new();
2320
Action<HttpClient> configureClient = null!;
24-
var handlers = Enumerable.Empty<DelegatingHandler>();
25-
26-
var exception = Assert.Throws<ArgumentNullException>(() => sut.CreateClient(configureClient, handlers));
21+
22+
var exception = Assert.Throws<ArgumentNullException>(() => sut.CreateClient(configureClient, []));
2723
Assert.Equal("configureClient", exception.ParamName);
2824
}
2925

@@ -42,33 +38,30 @@ static void configureClient(HttpClient _) { }
4238
[Fact]
4339
public void CreateClientWithConfigurerAndHttpMessageHandlers_CallsConfigureClientWithClientToReturn()
4440
{
41+
HttpClient? capturedClient = null;
4542
using TestableHttpMessageHandler sut = new();
46-
var configureClient = Substitute.For<Action<HttpClient>>();
47-
var handlers = Enumerable.Empty<DelegatingHandler>();
48-
49-
using var client = sut.CreateClient(configureClient, handlers);
43+
void configureClient(HttpClient client) => capturedClient = client;
44+
45+
using var client = sut.CreateClient(configureClient, []);
5046

51-
configureClient.Received(1).Invoke(client);
47+
Assert.Same(client, capturedClient);
5248
}
5349

5450
[Fact]
5551
public void CreateClientWithConfigurerAndHttpMessageHandlers_WhenHttpMessageHandlersArePassed_HandlersAreCorrectlyLinked()
5652
{
5753
using TestableHttpMessageHandler sut = new();
5854
static void configureClient(HttpClient _) { }
59-
IEnumerable<DelegatingHandler> handlers =
60-
[
61-
Substitute.For<DelegatingHandler>(),
62-
Substitute.For<DelegatingHandler>()
63-
];
55+
using TestDelegateHandler delegate1 = new();
56+
using TestDelegateHandler delegate2 = new();
6457

65-
using var client = sut.CreateClient(configureClient, handlers);
58+
using var client = sut.CreateClient(configureClient, [delegate1, delegate2]);
6659

6760
var handler = GetPrivateHandler(client);
6861
var delegatingHandler1 = Assert.IsAssignableFrom<DelegatingHandler>(handler);
69-
Assert.Same(handlers.First(), delegatingHandler1);
62+
Assert.Same(delegate1, delegatingHandler1);
7063
var delegatingHandler2 = Assert.IsAssignableFrom<DelegatingHandler>(delegatingHandler1.InnerHandler);
71-
Assert.Same(handlers.Last(), delegatingHandler2);
64+
Assert.Same(delegate2, delegatingHandler2);
7265
Assert.Same(sut, delegatingHandler2.InnerHandler);
7366
}
7467

@@ -77,13 +70,10 @@ public void CreateClientWithConfigurerAndHttpMessageHandlers_ByDefault_SetsDefau
7770
{
7871
using TestableHttpMessageHandler sut = new();
7972
static void configureClient(HttpClient client) { }
80-
IEnumerable<DelegatingHandler> handlers =
81-
[
82-
Substitute.For<DelegatingHandler>(),
83-
Substitute.For<DelegatingHandler>()
84-
];
73+
using TestDelegateHandler delegate1 = new();
74+
using TestDelegateHandler delegate2 = new();
8575

86-
using var client = sut.CreateClient(configureClient, handlers);
76+
using var client = sut.CreateClient(configureClient, [delegate1, delegate2]);
8777

8878
Assert.Equal(new Uri("https://localhost"), client.BaseAddress);
8979
}
@@ -93,15 +83,14 @@ public void CreateClientWithConfigurerAndHttpMessageHandlers_WhenConfiguringBase
9383
{
9484
using TestableHttpMessageHandler sut = new();
9585
static void configureClient(HttpClient client) { client.BaseAddress = new Uri("https://example"); }
96-
IEnumerable<DelegatingHandler> handlers =
97-
[
98-
Substitute.For<DelegatingHandler>(),
99-
Substitute.For<DelegatingHandler>()
100-
];
86+
using TestDelegateHandler delegate1 = new();
87+
using TestDelegateHandler delegate2 = new();
10188

102-
using var client = sut.CreateClient(configureClient, handlers);
89+
using var client = sut.CreateClient(configureClient, [delegate1, delegate2]);
10390

10491
Assert.Equal(new Uri("https://example"), client.BaseAddress);
10592
}
93+
94+
private sealed class TestDelegateHandler : DelegatingHandler { }
10695
}
10796

test/TestableHttpClient.Tests/TestableHttpMessageHandlerTests.cs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
using System.Collections.Concurrent;
22
using System.Threading;
33

4-
using NSubstitute;
5-
64
namespace TestableHttpClient.Tests;
75

86
public class TestableHttpMessageHandlerTests
@@ -40,18 +38,16 @@ public async Task SendAsync_WhenMultipleRequestsAreMade_AllRequestsAreLogged()
4038
[Fact]
4139
public async Task SendAsync_ByDefault_CallsExecutAsyncOnIResponse()
4240
{
43-
IResponse mockedResponse = Substitute.For<IResponse>();
41+
CustomResponse mockedResponse = new();
4442
HttpResponseContext? context = null;
45-
mockedResponse.ExecuteAsync(Arg.Any<HttpResponseContext>(), Arg.Any<CancellationToken>())
46-
.Returns(Task.CompletedTask)
47-
.AndDoes(x => context = x[0] as HttpResponseContext);
4843

4944
using TestableHttpMessageHandler sut = new();
5045
sut.RespondWith(mockedResponse);
5146
using HttpClient client = new(sut);
5247
using HttpRequestMessage request = new(HttpMethod.Get, new Uri("https://example.com/"));
5348
using HttpResponseMessage response = await client.SendAsync(request, TestContext.Current.CancellationToken);
5449

50+
context = mockedResponse.Context;
5551
Assert.NotNull(context);
5652
Assert.Same(request, context.HttpRequestMessage);
5753
Assert.Same(response, context.HttpResponseMessage);
@@ -142,7 +138,7 @@ public async Task ClearRequests_ByDefault_ShouldClearRequests()
142138
public void GetAsync_ShouldNotHang()
143139
{
144140
using TestableHttpMessageHandler sut = new();
145-
sut.RespondWith(Responses.Delayed(new CustomResponse(), TimeSpan.FromSeconds(1)));
141+
sut.RespondWith(Responses.Delayed(new CustomAsyncResponse(), TimeSpan.FromSeconds(1)));
146142

147143
bool doesNotHang = Task.Run(() =>
148144
{
@@ -157,6 +153,18 @@ public void GetAsync_ShouldNotHang()
157153
}
158154

159155
private sealed class CustomResponse : IResponse
156+
{
157+
public HttpResponseContext? Context { get; private set; }
158+
159+
public Task ExecuteAsync(HttpResponseContext context, CancellationToken cancellationToken)
160+
{
161+
Context = context;
162+
return Task.CompletedTask;
163+
}
164+
}
165+
166+
// This class intentionally used the wrong patterns for running async code, please do not use in production!
167+
private sealed class CustomAsyncResponse : IResponse
160168
{
161169
public Task ExecuteAsync(HttpResponseContext context, CancellationToken cancellationToken)
162170
{

0 commit comments

Comments
 (0)