

Test Your .NET HttpClient Based Strongly Typed Clients Like a Boss
source link: https://adamstorr.azurewebsites.net/blog/test-your-dotnet-httpclient-based-strongly-typed-clients-like-a-boss
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Test Your .NET HttpClient Based Strongly Typed Clients Like a Boss
Looking at using HttpClient Interception library to setup and create a HttpClient instance to allow for testing strongly typed client classes.
Published on 29 June 2021
Introduction
Up until now we have been concentrating on how to setup the HttpClient Interception library to mimic http requests, setup matches and specify the test content we want. In this post we will look at how we can use the library to test our own code which relies on a HttpClient instance to make requests.
Historically writing tests against HttpClient related functionality was potentially tricky. Either you would mock out the service which interacted with the HttpClient instance so the calling code could setup expectations on the interface etc. and not have to worry about the infrastructure or you would have to dive manually into DelegatingHandlers. These two levels of abstraction both have pros and cons to them. Mocking the "level above" gives you full control in your tests but means you don't test your code which interacts with HttpClient. Going into the world of DelegatingHandlers gives you the control of flow and allows for testing your code. It does however mean you need to understand a level of abstraction down into the framework which you may not be comfortable with.
What the HttpClient Interception library does is give the power of using DelegatingHandlers without the learning curve of having to work directly yourself. This gives you the power to specify stock responses as we've seen in earlier posts and then using the generated HttpClient instance we can pass this into the System Under Test, or SUT, which is ultimately what we want to test.
Basic Strongly Typed Client Setup
To demonstrate how to do this we will create a simple strongly typed client over HttpClient. To keep with the theme and familiarity this sticks with the functionality with calls to the GitHub API to request details of a user from a specified username.
public class MySimpleGithubClient
{
private readonly HttpClient _httpClient;
public MySimpleGithubClient(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<GitHubUser> GetUserAsync(string name)
{
var response = await _httpClient.GetAsync($"/users/{name}");
var responseAsString = await response.Content.ReadAsStringAsync();
return System.Text.Json.JsonSerializer.Deserialize<GitHubUser>(responseAsString);
}
}
In the example above we have a strongly typed client which takes a HttpClient in it's constructor. We then have a GetUserAsync
method which takes the required username and returns a GitHubUser
instance created from the response.
The expectation of the class is the base uri for the HttpClient has already been set and this class is responsible for calling the specific path to make the request. Please note this is a simple example and does not deal with failures which would need to be addressed in a production system.
A call to the method constructs the path and makes the request. Once a request has returned the content of the response body is read and serialized into the object we expect to be returned. We want to get a test to check that this "happy path" runs as expected and then will allow for further extension of error handling etc. to be able to be added with confidence of existing processing working.
public class GitHubUser
{
[JsonPropertyName("name")]
public string Name { get; set; }
}
The above is the simple model class we are looking to populate and return from the strongly typed client method.
Test The Client
How do we setup the test for this strongly typed client? As with all the tests I write I like to follow the AAA, or "Arrange, Act, Assert", syntax which allows for a clear layout of the test.
As discussed previously we need to setup the HttpClientInterceptorOptions
with the HttpRequestInterceptionBuilder
functionality we've seen before. As part of this we're going to return an anonymous type as json to restrict the payload for testing and not use a bundle but this could also be setup with a bundle.
Once the setup for the request has been created and the HttpClient
instance has been created with the base URI we can instantiate our SUT passing in the HttpClient
. This can now be executed and the result returned can be checked after the result has been returned.
[Fact]
public async Task GetUser_Returns_Success()
{
// Arrange
var builder = new HttpRequestInterceptionBuilder()
.ForHost("api.github.com")
.ForPath("users/WestDiscGolf")
.ForHttps()
.ForMethod(HttpMethod.Get)
.WithJsonContent(new { login = "WestDiscGolf", name = "Adam Storr" });
var options = new HttpClientInterceptorOptions().Register(builder);
var client = options.CreateHttpClient(new Uri("https://api.github.com/"));
var sut = new MySimpleGithubClient(client);
// Act
var result = await sut.GetUserAsync("WestDiscGolf");
// Assert
result.Should().NotBeNull();
result.Name.Should().Be("Adam Storr");
}
We can now be confident that the above code has tested our simple strongly typed client on the Happy Path and can use that as a basis for further testing.
Conclusion
In this post we have looked at using the Just Eat HttpClient Interception library to start testing our own strongly typed HttpClient based client code. This allows for a lot of power a flexibility to test code which otherwise would require a lot of processing and setup. This is the basis of further testing including error handling. It also allows for testing to work with extension libraries such as Polly to allow for configurable retries and back off strategies for connection requests.
If you’ve liked this post please check out my lightning talk about the basics of the library. In future posts I hope to continue to explore the library more so please subscribe to my rss feed (link below) and reach out to me on Twitter if you have any comments.
Recommend
-
61
Redux is a popular library used to manage state in React apps. How can we make our Redux code strongly-typed with TypeScript – particularly when we have asynchronous code in the mix? L...
-
35
xUnit has a quirky system for consuming test data. Strongly typed test data can be specified with the MemberData attribute and the Theory attribute but it’s not intuitive. The MemberData...
-
40
Destructuring assignment and...
-
14
TypeScript, Knockout, TypeLite; strongly typed knockout development TypeScript’s a great environment for development, and the strong typing is a real benefit, but in an MVC app it’d be...
-
15
Taming dictionaries to strongly-typed interfaces with Castle DictionaryAdapter So Castle is one of those projects that seems to sit behind a lot of technologies (Moq,
-
8
posts C# 9 records as strongly-typed ids - Part 4: Entity Framework Core integration December 23, 2020Created by Wireformfrom the Noun Project
-
9
Removing IOptions From Your Strongly Typed Configuration in Azure Functions Want to strongly type your configuration but don't like IOptions? Let's take a look how to do this in Azure Functions. Publish...
-
10
CSS is a Strongly Typed Language Eric Bailey on Apr 13, 2021 Take the pain out of building site search with the Algolia hosted API. ...
-
11
Introducing GraphQLinq - Strongly Typed GraphQL Queries with LINQ to GraphQL.Apr 27, 2021 3 min read dotnetConsuming a GraphQL api in C# is straightforward...
-
7
Stringly Typed vs Strongly Typed Sponsored By I used to call this technique "type t...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK