Skip to content

Commit 92a749a

Browse files
authored
Verifable (#12)
- Fixes #2 - Number of times the request was called, now recorded. - BREAKING CHANGE: Constructors were simplified to all use the same main `HttpMessageOptions` class.
1 parent e7413d3 commit 92a749a

File tree

3 files changed

+97
-68
lines changed

3 files changed

+97
-68
lines changed

src/HttpClient.Helpers/FakeMessageHandler.cs

Lines changed: 22 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Linq;
44
using System.Net;
55
using System.Net.Http;
6+
using System.Reflection;
67
using System.Text;
78
using System.Threading;
89
using System.Threading.Tasks;
@@ -16,22 +17,6 @@ public class FakeHttpMessageHandler : HttpClientHandler
1617
private readonly IDictionary<string, HttpMessageOptions> _lotsOfOptions = new Dictionary<string, HttpMessageOptions>();
1718

1819

19-
/// <summary>
20-
/// A fake message handler.
21-
/// </summary>
22-
/// <remarks>This is mainly used for unit testing purposes.</remarks>
23-
/// <param name="requestUri">The endpoint the HttpClient would normally try and connect to.</param>
24-
/// <param name="httpResponseMessage">The faked response message.</param>
25-
public FakeHttpMessageHandler(string requestUri,
26-
HttpResponseMessage httpResponseMessage)
27-
: this(new HttpMessageOptions
28-
{
29-
RequestUri = requestUri,
30-
HttpResponseMessage = httpResponseMessage
31-
})
32-
{
33-
}
34-
3520
/// <summary>
3621
/// A fake message handler.
3722
/// </summary>
@@ -58,47 +43,11 @@ public FakeHttpMessageHandler(HttpMessageOptions options) : this(new List<HttpMe
5843
{
5944
}
6045

61-
public FakeHttpMessageHandler(IDictionary<string, HttpResponseMessage> responses)
62-
{
63-
if (responses == null)
64-
{
65-
throw new ArgumentNullException(nameof(responses));
66-
}
67-
68-
if (!responses.Any())
69-
{
70-
throw new ArgumentOutOfRangeException(nameof(responses));
71-
}
72-
73-
// NOTE: We assume HttpGet is the default when none are provided in this 'shortcut' method.
74-
var lotsOfOptions = responses.Select(item => new HttpMessageOptions
75-
{
76-
RequestUri = item.Key,
77-
HttpResponseMessage = item.Value,
78-
HttpMethod = HttpMethod.Get
79-
}).ToArray();
80-
81-
Initialize(lotsOfOptions);
82-
}
83-
8446
public FakeHttpMessageHandler(IEnumerable<HttpMessageOptions> lotsOfOptions)
8547
{
8648
Initialize(lotsOfOptions.ToArray());
8749
}
8850

89-
/// <summary>
90-
/// A fake message handler which ignores whatever endpoint you're trying to connect to.
91-
/// </summary>
92-
/// <remarks>This constructor doesn't care what the request endpoint it. So if you're code is trying to hit multuple endpoints, then it will always return the same response message.</remarks>
93-
/// <param name="httpResponseMessage">The faked response message.</param>
94-
public FakeHttpMessageHandler(HttpResponseMessage httpResponseMessage)
95-
: this(new HttpMessageOptions
96-
{
97-
HttpResponseMessage = httpResponseMessage
98-
})
99-
{
100-
}
101-
10251
/// <summary>
10352
/// A fake message handler for an exception.
10453
/// </summary>
@@ -149,6 +98,9 @@ protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage reques
14998
throw new InvalidOperationException(errorMessage);
15099
}
151100

101+
// Increment the number of times this option had been 'called'.
102+
IncrementCalls(expectedOption);
103+
152104
tcs.SetResult(expectedOption.HttpResponseMessage);
153105
return tcs.Task;
154106
}
@@ -207,5 +159,23 @@ private HttpMessageOptions GetExpectedOption(HttpMessageOptions option)
207159
(x.HttpContent == option.HttpContent ||
208160
x.HttpContent == null));
209161
}
162+
163+
private static void IncrementCalls(HttpMessageOptions options)
164+
{
165+
if (options == null)
166+
{
167+
throw new ArgumentNullException(nameof(options));
168+
}
169+
170+
var type = typeof(HttpMessageOptions);
171+
var propertyInfo = type.GetProperty("NumberOfTimesCalled");
172+
if (propertyInfo == null)
173+
{
174+
return;
175+
}
176+
177+
var existingValue = (int) propertyInfo.GetValue(options);
178+
propertyInfo.SetValue(options, ++existingValue);
179+
}
210180
}
211181
}

src/HttpClient.Helpers/HttpMessageOptions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ public HttpContent HttpContent
5151
}
5252
}
5353

54+
public int NumberOfTimesCalled { get; private set; }
55+
5456
public override string ToString()
5557
{
5658
var httpMethodText = HttpMethod?.ToString() ?? NoValue;

tests/HttpClient.Helpers.Tests/GetAsyncTests.cs

Lines changed: 73 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Linq;
34
using System.Net;
45
using System.Net.Http;
56
using System.Threading.Tasks;
@@ -119,72 +120,103 @@ public static IEnumerable<object[]> ValidSomeHttpMessageOptions
119120

120121
[Theory]
121122
[MemberData(nameof(ValidHttpMessageOptions))]
122-
public async Task GivenAnHttpMessageOptions_GetAsync_ReturnsAFakeResponse(HttpMessageOptions option)
123+
public async Task GivenAnHttpMessageOptions_GetAsync_ReturnsAFakeResponse(HttpMessageOptions options)
123124
{
124-
var fakeHttpMessageHandler = new FakeHttpMessageHandler(option);
125+
// Arrange.
126+
var fakeHttpMessageHandler = new FakeHttpMessageHandler(options);
125127

128+
// Act & Assert.
126129
await DoGetAsync(RequestUri,
127130
ExpectedContent,
128131
fakeHttpMessageHandler);
132+
options.NumberOfTimesCalled.ShouldBe(1);
129133
}
130134

131135
[Theory]
132136
[MemberData(nameof(ValidSomeHttpMessageOptions))]
133-
public async Task GivenSomeHttpMessageOptions_GetAsync_ReturnsAFakeResponse(IEnumerable<HttpMessageOptions> lotsOfOption)
137+
public async Task GivenSomeHttpMessageOptions_GetAsync_ReturnsAFakeResponse(IList<HttpMessageOptions> lotsOfOptions)
134138
{
135-
var fakeHttpMessageHandler = new FakeHttpMessageHandler(lotsOfOption);
139+
// Arrange.
140+
var fakeHttpMessageHandler = new FakeHttpMessageHandler(lotsOfOptions);
136141

142+
// Act & Assert.
137143
await DoGetAsync(RequestUri,
138144
ExpectedContent,
139145
fakeHttpMessageHandler);
146+
lotsOfOptions.Sum(x => x.NumberOfTimesCalled).ShouldBe(1);
140147
}
141148

142149
[Fact]
143150
public async Task GivenAnHttpResponseMessage_GetAsync_ReturnsAFakeResponse()
144151
{
152+
// Arrange.
145153
var httpResponseMessage = FakeHttpMessageHandler.GetStringHttpResponseMessage(ExpectedContent);
146-
var fakeHttpMessageHandler = new FakeHttpMessageHandler(httpResponseMessage);
154+
var options = new HttpMessageOptions
155+
{
156+
HttpResponseMessage = httpResponseMessage
157+
};
158+
var fakeHttpMessageHandler = new FakeHttpMessageHandler(options);
147159

160+
// Act & Assert.
148161
await DoGetAsync(RequestUri,
149162
ExpectedContent,
150163
fakeHttpMessageHandler);
164+
options.NumberOfTimesCalled.ShouldBe(1);
151165
}
152166

153167
[Fact]
154168
public async Task GivenSomeHttpResponseMessages_GetAsync_ReturnsAFakeResponse()
155169
{
156-
const string requestUrl1 = RequestUri;
157-
const string responseData1 = ExpectedContent;
158-
var messageResponse1 = FakeHttpMessageHandler.GetStringHttpResponseMessage(responseData1);
170+
// Arrange.
171+
var messageResponse1 = FakeHttpMessageHandler.GetStringHttpResponseMessage(ExpectedContent);
159172

160-
const string requestUrl2 = "http://www.something.com/another/site";
161173
const string responseData2 = "Html, I am not.";
162174
var messageResponse2 = FakeHttpMessageHandler.GetStringHttpResponseMessage(responseData2);
163175

164-
const string requestUrl3 = "http://www.whatever.com/";
165176
const string responseData3 = "<html><head><body>pew pew</body></head>";
166177
var messageResponse3 = FakeHttpMessageHandler.GetStringHttpResponseMessage(responseData3);
167178

168-
var messageResponses = new Dictionary<string, HttpResponseMessage>
179+
var options = new List<HttpMessageOptions>
169180
{
170-
{requestUrl1, messageResponse1},
171-
{requestUrl2, messageResponse2},
172-
{requestUrl3, messageResponse3}
181+
new HttpMessageOptions
182+
{
183+
RequestUri = RequestUri,
184+
HttpResponseMessage = messageResponse1
185+
},
186+
new HttpMessageOptions
187+
{
188+
RequestUri = "http://www.something.com/another/site",
189+
HttpResponseMessage = messageResponse2
190+
},
191+
new HttpMessageOptions
192+
{
193+
RequestUri = "http://www.whatever.com/",
194+
HttpResponseMessage = messageResponse3
195+
},
173196
};
174197

175-
var fakeHttpMessageHandler = new FakeHttpMessageHandler(messageResponses);
198+
var fakeHttpMessageHandler = new FakeHttpMessageHandler(options);
176199

200+
// Act & Assert.
177201
await DoGetAsync(RequestUri,
178202
ExpectedContent,
179203
fakeHttpMessageHandler);
204+
options[0].NumberOfTimesCalled.ShouldBe(1);
205+
options[1].NumberOfTimesCalled.ShouldBe(0);
206+
options[2].NumberOfTimesCalled.ShouldBe(0);
180207
}
181208

182209
[Fact]
183210
public async Task GivenAnUnauthorisedStatusCodeResponse_GetAsync_ReturnsAFakeResponseWithAnUnauthorisedStatusCode()
184211
{
185212
// Arrange.
186213
var messageResponse = FakeHttpMessageHandler.GetStringHttpResponseMessage("pew pew", HttpStatusCode.Unauthorized);
187-
var messageHandler = new FakeHttpMessageHandler(RequestUri, messageResponse);
214+
var options = new HttpMessageOptions
215+
{
216+
RequestUri = RequestUri,
217+
HttpResponseMessage = messageResponse
218+
};
219+
var messageHandler = new FakeHttpMessageHandler(options);
188220

189221
HttpResponseMessage message;
190222
using (var httpClient = new System.Net.Http.HttpClient(messageHandler))
@@ -195,6 +227,7 @@ public async Task GivenAnUnauthorisedStatusCodeResponse_GetAsync_ReturnsAFakeRes
195227

196228
// Assert.
197229
message.StatusCode.ShouldBe(HttpStatusCode.Unauthorized);
230+
options.NumberOfTimesCalled.ShouldBe(1);
198231
}
199232

200233
[Fact]
@@ -217,6 +250,30 @@ public async Task GivenAValidHttpRequest_GetSomeDataAsync_ReturnsAFoo()
217250
exception.Message.ShouldBe(errorMessage);
218251
}
219252

253+
[Fact]
254+
public async Task GivenAFewCallsToAnHttpRequest_GetSomeDataAsync_ReturnsAFakeResponse()
255+
{
256+
// Arrange.
257+
var httpResponseMessage = FakeHttpMessageHandler.GetStringHttpResponseMessage(ExpectedContent);
258+
var options = new HttpMessageOptions
259+
{
260+
HttpResponseMessage = httpResponseMessage
261+
};
262+
var fakeHttpMessageHandler = new FakeHttpMessageHandler(options);
263+
264+
// Act & Assert
265+
await DoGetAsync(RequestUri,
266+
ExpectedContent,
267+
fakeHttpMessageHandler);
268+
await DoGetAsync(RequestUri,
269+
ExpectedContent,
270+
fakeHttpMessageHandler);
271+
await DoGetAsync(RequestUri,
272+
ExpectedContent,
273+
fakeHttpMessageHandler);
274+
options.NumberOfTimesCalled.ShouldBe(3);
275+
}
276+
220277
private static async Task DoGetAsync(string requestUri,
221278
string expectedResponseContent,
222279
FakeHttpMessageHandler fakeHttpMessageHandler)

0 commit comments

Comments
 (0)