Skip to content

Commit fe9417c

Browse files
authored
Add NFluent checks for TestableHttpMessageHandler.
With these NFluent checks, it is now possible to make the same assertions using either the build in checks or the NFluent checks: ```csharp var handler = new TestableHttpHandler(); handler.ShouldHaveMadeRequests().WithHttpMethod(HttpMethod.Post); Check.That(handler).HasMadeRequests().WithHttpMethod(HttpMethod.Post); ``` Closes # 31.
1 parent 7a0a11d commit fe9417c

27 files changed

+690
-79
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

77
## [Unreleased]
8+
### Added
9+
- It is now possible to use NFluent to check `TestableHttpMessageHandler` by using `Check.That(handler).HasMadeRequests()` and `Check.That(handler).HasMadeRequestsTo("https://github.com/dnperfors/testablehttpclient")`. All existing `With` checks are supported.
810
### Changed
911
- Introduced `IHttpRequestMessagesCheck` as the public interface for all checks on requests made to `TestableHttpMessageHandler`. It contains the following api:
1012
- `With(Func<HttpRequestMessage, bool>, string)`

README.md

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ This repository contains multiple related libraries. The separation is mainly ma
99
|Libary|Description|Main dependency|Nuget|
1010
|------|-----------|---------------|-----|
1111
|TestableHttpClient|Basic library for mocking HttpMessageHandler and to make manual assertions on HttpResponseMessage.|None|![Nuget](https://img.shields.io/nuget/v/TestableHttpClient)|
12-
|TestableHttpClient.NFluent|Library containing [NFluent](https://github.com/tpierrain/NFluent) checks for HttpResponseMessage. Currently there is no dependency between the two libraries.|NFluent|![Nuget](https://img.shields.io/nuget/v/TestableHttpClient.NFluent)|
12+
|TestableHttpClient.NFluent|Library containing [NFluent](https://github.com/tpierrain/NFluent) checks for HttpResponseMessage and TestableHttpMessageHandler.|NFluent|![Nuget](https://img.shields.io/nuget/v/TestableHttpClient.NFluent)|
1313

1414
## How to install
1515

@@ -22,9 +22,9 @@ dotnet add package TestableHttpClient.NFluent
2222

2323
## How to use TestableHttpClient
2424

25-
```c#
25+
```csharp
2626
var testHandler = new TestableHttpMessageHandler();
27-
var httpClient = new HttpClient(testHandler);
27+
var httpClient = new HttpClient(testHandler); // or testHandler.CreateClient();
2828
2929
var result = await httpClient.GetAsync("http://httpbin.org/status/200");
3030

@@ -33,16 +33,27 @@ testHandler.ShouldHaveMadeRequestsTo("https://httpbin.org/*");
3333

3434
More examples can be found in the [IntegrationTests project](test/TestableHttpClient.IntegrationTests)
3535

36-
## How to use TestableHttpClient.NFluent
36+
## How to use TestableHttpClient.NFluent to test responses
3737

38-
```c#
38+
```csharp
3939
var client = new HttpClient();
4040

4141
var result = await httpClient.GetAsync("https://httpbin.org/status/200");
4242

4343
Check.That(result).HasStatusCode(HttpStatusCode.OK).And.HasContentHeader("Content-Type", "*/json*");
4444
```
4545

46+
## How to use TestableHttpClient.NFluent to which requests are made
47+
48+
```csharp
49+
var testHandler = new TestableHttpMessageHandler();
50+
var httpClient = new HttpClient(testHandler); // or testHandler.CreateClient();
51+
52+
var result = await httpClient.GetAsync("http://httpbin.org/status/200");
53+
54+
Check.That(testHandler).HasMadeRequestsTo("https://httpbin.org/*");
55+
```
56+
4657
## Contributing
4758

4859
Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on how you can help us out.

TestableHttpClient.sln

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestableHttpClient.NFluent"
2525
EndProject
2626
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestableHttpClient.NFluent.Tests", "test\TestableHttpClient.NFluent.Tests\TestableHttpClient.NFluent.Tests.csproj", "{29F350FB-5901-41AC-8605-F3413EE49E4A}"
2727
EndProject
28-
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "SharedUtilities", "src\SharedUtilities\SharedUtilities.shproj", "{E405AF28-9C17-4580-AEBD-58B1BD4B116C}"
29-
EndProject
3028
Global
31-
GlobalSection(SharedMSBuildProjectFiles) = preSolution
32-
src\SharedUtilities\SharedUtilities.projitems*{127e2f48-cb33-488e-88e3-1bb0043c8cc1}*SharedItemsImports = 5
33-
src\SharedUtilities\SharedUtilities.projitems*{e405af28-9c17-4580-aebd-58b1bd4b116c}*SharedItemsImports = 13
34-
src\SharedUtilities\SharedUtilities.projitems*{fd5111e1-2970-4dc4-84dd-e4966e17dcb3}*SharedItemsImports = 5
35-
EndGlobalSection
3629
GlobalSection(SolutionConfigurationPlatforms) = preSolution
3730
Debug|Any CPU = Debug|Any CPU
3831
Debug|x64 = Debug|x64
@@ -112,7 +105,6 @@ Global
112105
{37A6C1C0-1117-43DE-BD15-290BC8AD32BE} = {BBCED492-E92B-4FA8-A4A5-B5A76091F25E}
113106
{127E2F48-CB33-488E-88E3-1BB0043C8CC1} = {4C8914F8-D732-462B-978E-3BB5DBE547D7}
114107
{29F350FB-5901-41AC-8605-F3413EE49E4A} = {BBCED492-E92B-4FA8-A4A5-B5A76091F25E}
115-
{E405AF28-9C17-4580-AEBD-58B1BD4B116C} = {4C8914F8-D732-462B-978E-3BB5DBE547D7}
116108
EndGlobalSection
117109
GlobalSection(ExtensibilityGlobals) = postSolution
118110
SolutionGuid = {CD31CAB7-6661-4E80-9A70-BC8BA6B9B764}

src/SharedUtilities/SharedUtilities.projitems

Lines changed: 0 additions & 14 deletions
This file was deleted.

src/SharedUtilities/SharedUtilities.shproj

Lines changed: 0 additions & 13 deletions
This file was deleted.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
using System.Runtime.CompilerServices;
2+
3+
[assembly: InternalsVisibleTo("TestableHttpClient.NFluent.Tests")]
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Net.Http;
5+
6+
using NFluent;
7+
using NFluent.Extensibility;
8+
using NFluent.Kernel;
9+
10+
using TestableHttpClient.Utils;
11+
12+
namespace TestableHttpClient.NFluent
13+
{
14+
/// <summary>
15+
/// Class that implement NFluent checks on a collection of HttpRequestMessages.
16+
/// </summary>
17+
internal class FluentHttpRequestMessagesChecks : FluentSut<IEnumerable<HttpRequestMessage>>, IHttpRequestMessagesCheck
18+
{
19+
private IEnumerable<HttpRequestMessage> requests;
20+
private readonly List<string> requestConditions = new List<string>();
21+
22+
public FluentHttpRequestMessagesChecks(IEnumerable<HttpRequestMessage> httpRequestMessages)
23+
: base(httpRequestMessages, Check.Reporter, false)
24+
{
25+
if (httpRequestMessages == null)
26+
{
27+
throw new ArgumentNullException(nameof(httpRequestMessages));
28+
}
29+
requests = httpRequestMessages;
30+
}
31+
32+
public IHttpRequestMessagesCheck With(Func<HttpRequestMessage, bool> predicate, string message)
33+
{
34+
if (!string.IsNullOrEmpty(message))
35+
{
36+
requestConditions.Add(message);
37+
}
38+
39+
var checkLogic = ExtensibilityHelper.BeginCheck(this)
40+
.CantBeNegated(nameof(With))
41+
.FailWhen(_ => predicate == null, "The predicate should not be null.", MessageOption.NoCheckedBlock | MessageOption.NoExpectedBlock)
42+
.Analyze((sut, _) => requests = requests.Where(predicate));
43+
44+
AnalyzeNumberOfRequests(checkLogic, null);
45+
return this;
46+
}
47+
48+
public IHttpRequestMessagesCheck Times(int count)
49+
{
50+
var checkLogic = ExtensibilityHelper.BeginCheck(this)
51+
.CantBeNegated(nameof(Times))
52+
.SetSutName("number of requests")
53+
.DefineExpectedResult(count, null, null)
54+
.FailWhen(_ => count < 0, "The {1} should not be below zero.", MessageOption.NoCheckedBlock);
55+
AnalyzeNumberOfRequests(checkLogic, count);
56+
return this;
57+
}
58+
59+
private void AnalyzeNumberOfRequests(ICheckLogic<IEnumerable<HttpRequestMessage>> checkLogic, int? expectedCount)
60+
{
61+
checkLogic.Analyze((sut, check) =>
62+
{
63+
var actualCount = requests.Count();
64+
var pass = expectedCount switch
65+
{
66+
null => actualCount > 0,
67+
_ => actualCount == expectedCount
68+
};
69+
70+
var message = MessageBuilder.BuildMessage(expectedCount, actualCount, requestConditions);
71+
if (!pass)
72+
{
73+
check.Fail(message, MessageOption.NoCheckedBlock | MessageOption.NoExpectedBlock);
74+
}
75+
})
76+
.EndCheck();
77+
}
78+
}
79+
}

src/TestableHttpClient.NFluent/HttpResponseMessageChecks.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
using NFluent;
77
using NFluent.Extensibility;
88

9+
using TestableHttpClient.Utils;
10+
911
namespace TestableHttpClient.NFluent
1012
{
1113
/// <summary>

src/TestableHttpClient.NFluent/README.md

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
# TestableHttpClient.NFluent
22

3-
In integration tests, asserting HttpResponseMessages can be a real challenge, especially since error messages are sometimes not very clear. NFluent is known for giving clear error messages and `TestableHttpClient.NFluent` is designed to easily verify HttpResponseMessages and give clear error messages.
3+
In integration tests, asserting HttpResponseMessages can be a real challenge, especially since error messages are sometimes not very clear. NFluent is known for giving clear error messages.
4+
`TestableHttpClient.NFluent` is designed to make it easier to check `HttpResponseMessage`s and `TestableHttpClient`s and give clear error messages.
45

56
For example when the following check fails:
6-
```c#
7+
```csharp
78
Check.That(response).HasResponseHeader("Server");
89
```
910
it will return the following message:
@@ -24,14 +25,27 @@ dotnet add package TestableHttpClient.NFluent
2425

2526
## How to use
2627

27-
```c#
28+
### Asserting HttpResponseMessages
29+
30+
```csharp
2831
var client = new HttpClient();
2932

3033
var result = await httpClient.GetAsync("https://httpbin.org/status/200");
3134

3235
Check.That(result).HasStatusCode(HttpStatusCode.OK).And.HasContentHeader("Content-Type", "*/json*");
3336
```
3437

38+
### Asserting TestableHttpMessageHandler
39+
40+
```csharp
41+
var handler = new TestableHttpMessageHandler();
42+
var client = new HttpClient(handler);
43+
44+
_ = await httpClient.GetAsync("https://httpbin.org/status/200");
45+
46+
Check.That(handler).HasMadeRequestsTo("https://httpbin.org*").WithHttpMethod(HttpMethod.Get);
47+
```
48+
3549
## Authors
3650

3751
* **David Perfors** - [dnperfors](https://github.com/dnperfors)
@@ -40,4 +54,4 @@ See also the list of [contributors](https://github.com/dnperfors/TestableHttpCli
4054

4155
## License
4256

43-
This project is released under the MIT license, see [LICENSE.md](LICENSE.md) for more information.
57+
This project is released under the MIT license, see [LICENSE.md](../../LICENSE.md) for more information.

src/TestableHttpClient.NFluent/TestableHttpClient.NFluent.csproj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
<PackageReference Include="NFluent" Version="2.7.0" />
1616
</ItemGroup>
1717

18-
<Import Project="..\SharedUtilities\SharedUtilities.projitems" Label="Shared" />
18+
<ItemGroup>
19+
<ProjectReference Include="..\TestableHttpClient\TestableHttpClient.csproj" />
20+
</ItemGroup>
1921

2022
</Project>

0 commit comments

Comments
 (0)